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 Stockner <lukas.stockner@freenet.de>2017-02-01 20:07:35 +0300
committerLukas Stockner <lukas.stockner@freenet.de>2017-02-01 20:07:35 +0300
commit71e1c3bc4b89a5b436f2b864ffb24150b29d74a0 (patch)
tree717cf0848fa0f80bbb651bf04c6e04d9c7077e1a
parent671a28ae55235beabc579cf3e02439e07d661212 (diff)
parentfa19940dc63d22cc03e1411e2add8ec8647b5f28 (diff)
Merge remote-tracking branch 'origin/master' into soc-2016-cycles_denoising
-rw-r--r--CMakeLists.txt2
-rwxr-xr-xbuild_files/build_environment/install_deps.sh2
-rw-r--r--build_files/cmake/Modules/GTestTesting.cmake2
-rw-r--r--build_files/cmake/macros.cmake7
-rw-r--r--build_files/cmake/platform/platform_win32_msvc.cmake18
-rw-r--r--doc/python_api/sphinx_doc_gen.py11
-rwxr-xr-xdoc/python_api/sphinx_doc_update.py4
-rw-r--r--extern/gflags/README.blender4
-rw-r--r--extern/gflags/src/gflags.cc4
-rw-r--r--intern/cycles/CMakeLists.txt2
-rw-r--r--intern/cycles/app/cycles_xml.cpp2
-rw-r--r--intern/cycles/blender/addon/__init__.py16
-rw-r--r--intern/cycles/blender/addon/engine.py2
-rw-r--r--intern/cycles/blender/addon/properties.py29
-rw-r--r--intern/cycles/blender/addon/ui.py87
-rw-r--r--intern/cycles/blender/blender_curves.cpp132
-rw-r--r--intern/cycles/blender/blender_mesh.cpp7
-rw-r--r--intern/cycles/blender/blender_object_cull.cpp2
-rw-r--r--intern/cycles/blender/blender_session.cpp3
-rw-r--r--intern/cycles/blender/blender_shader.cpp9
-rw-r--r--intern/cycles/blender/blender_sync.cpp23
-rw-r--r--intern/cycles/bvh/bvh.cpp17
-rw-r--r--intern/cycles/bvh/bvh.h4
-rw-r--r--intern/cycles/bvh/bvh_build.cpp312
-rw-r--r--intern/cycles/bvh/bvh_build.h2
-rw-r--r--intern/cycles/bvh/bvh_node.cpp13
-rw-r--r--intern/cycles/bvh/bvh_node.h7
-rw-r--r--intern/cycles/bvh/bvh_params.h35
-rw-r--r--intern/cycles/device/device_cuda.cpp2
-rw-r--r--intern/cycles/kernel/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/bvh/bvh_shadow_all.h7
-rw-r--r--intern/cycles/kernel/bvh/bvh_subsurface.h2
-rw-r--r--intern/cycles/kernel/bvh/bvh_traversal.h15
-rw-r--r--intern/cycles/kernel/bvh/bvh_types.h14
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume.h2
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume_all.h1
-rw-r--r--intern/cycles/kernel/bvh/qbvh_shadow_all.h17
-rw-r--r--intern/cycles/kernel/bvh/qbvh_subsurface.h2
-rw-r--r--intern/cycles/kernel/bvh/qbvh_traversal.h19
-rw-r--r--intern/cycles/kernel/bvh/qbvh_volume.h2
-rw-r--r--intern/cycles/kernel/bvh/qbvh_volume_all.h2
-rw-r--r--intern/cycles/kernel/geom/geom.h2
-rw-r--r--intern/cycles/kernel/geom/geom_curve.h2
-rw-r--r--intern/cycles/kernel/geom/geom_motion_curve.h8
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle.h310
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle_intersect.h280
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle_shader.h123
-rw-r--r--intern/cycles/kernel/geom/geom_object.h1
-rw-r--r--intern/cycles/kernel/geom/geom_primitive.h5
-rw-r--r--intern/cycles/kernel/geom/geom_triangle.h16
-rw-r--r--intern/cycles/kernel/kernel_bake.h2
-rw-r--r--intern/cycles/kernel/kernel_debug.h14
-rw-r--r--intern/cycles/kernel/kernel_light.h2
-rw-r--r--intern/cycles/kernel/kernel_path.h36
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h22
-rw-r--r--intern/cycles/kernel/kernel_path_common.h2
-rw-r--r--intern/cycles/kernel/kernel_shader.h29
-rw-r--r--intern/cycles/kernel/kernel_types.h164
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp22
-rw-r--r--intern/cycles/kernel/osl/osl_services.h2
-rw-r--r--intern/cycles/kernel/shaders/node_light_path.osl10
-rw-r--r--intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h14
-rw-r--r--intern/cycles/kernel/split/kernel_scene_intersect.h3
-rw-r--r--intern/cycles/kernel/svm/svm_light_path.h2
-rw-r--r--intern/cycles/kernel/svm/svm_types.h2
-rw-r--r--intern/cycles/kernel/svm/svm_wireframe.h2
-rw-r--r--intern/cycles/render/buffers.cpp5
-rw-r--r--intern/cycles/render/film.cpp16
-rw-r--r--intern/cycles/render/image.cpp21
-rw-r--r--intern/cycles/render/image.h6
-rw-r--r--intern/cycles/render/integrator.cpp11
-rw-r--r--intern/cycles/render/integrator.h3
-rw-r--r--intern/cycles/render/mesh.cpp282
-rw-r--r--intern/cycles/render/mesh.h56
-rw-r--r--intern/cycles/render/mesh_subdivision.cpp2
-rw-r--r--intern/cycles/render/nodes.cpp21
-rw-r--r--intern/cycles/render/object.cpp8
-rw-r--r--intern/cycles/render/scene.h3
-rw-r--r--intern/cycles/render/session.cpp8
-rw-r--r--intern/cycles/render/tile.cpp2
-rw-r--r--intern/cycles/test/CMakeLists.txt15
-rw-r--r--intern/cycles/util/util_boundbox.h2
-rw-r--r--intern/cycles/util/util_math.h22
-rw-r--r--intern/cycles/util/util_version.h6
-rw-r--r--make.bat17
-rw-r--r--release/datafiles/blender_icons.svg118
-rw-r--r--release/datafiles/blender_icons16/icon16_collapsemenu.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_tria_down_bar.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_tria_left_bar.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_tria_right_bar.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_tria_up_bar.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_collapsemenu.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_tria_down_bar.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_tria_left_bar.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_tria_right_bar.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_tria_up_bar.datbin4120 -> 4120 bytes
m---------release/datafiles/locale0
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/startup/bl_operators/freestyle.py58
-rw-r--r--release/scripts/startup/bl_ui/properties_animviz.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_game.py159
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py65
-rw-r--r--release/scripts/startup/bl_ui/space_info.py2
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py3
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py16
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py6
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--release/scripts/templates_py/addon_add_object.py2
-rw-r--r--release/text/readme.html2
-rw-r--r--source/blender/alembic/CMakeLists.txt6
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c4
-rw-r--r--source/blender/blenkernel/BKE_deform.h9
-rw-r--r--source/blender/blenkernel/BKE_library.h5
-rw-r--r--source/blender/blenkernel/BKE_library_query.h29
-rw-r--r--source/blender/blenkernel/BKE_main.h23
-rw-r--r--source/blender/blenkernel/BKE_modifier.h6
-rw-r--r--source/blender/blenkernel/BKE_object.h5
-rw-r--r--source/blender/blenkernel/BKE_particle.h2
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h2
-rw-r--r--source/blender/blenkernel/BKE_sca.h6
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c15
-rw-r--r--source/blender/blenkernel/intern/action.c3
-rw-r--r--source/blender/blenkernel/intern/anim.c10
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c1
-rw-r--r--source/blender/blenkernel/intern/armature.c1
-rw-r--r--source/blender/blenkernel/intern/brush.c2
-rw-r--r--source/blender/blenkernel/intern/cachefile.c8
-rw-r--r--source/blender/blenkernel/intern/constraint.c2
-rw-r--r--source/blender/blenkernel/intern/customdata.c3
-rw-r--r--source/blender/blenkernel/intern/deform.c187
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c557
-rw-r--r--source/blender/blenkernel/intern/fcurve.c1
-rw-r--r--source/blender/blenkernel/intern/freestyle.c1
-rw-r--r--source/blender/blenkernel/intern/gpencil.c1
-rw-r--r--source/blender/blenkernel/intern/ipo.c1
-rw-r--r--source/blender/blenkernel/intern/key.c1
-rw-r--r--source/blender/blenkernel/intern/library.c260
-rw-r--r--source/blender/blenkernel/intern/library_query.c336
-rw-r--r--source/blender/blenkernel/intern/library_remap.c32
-rw-r--r--source/blender/blenkernel/intern/linestyle.c1
-rw-r--r--source/blender/blenkernel/intern/mask.c2
-rw-r--r--source/blender/blenkernel/intern/mball.c1
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c2
-rw-r--r--source/blender/blenkernel/intern/modifier.c3
-rw-r--r--source/blender/blenkernel/intern/nla.c2
-rw-r--r--source/blender/blenkernel/intern/node.c5
-rw-r--r--source/blender/blenkernel/intern/object.c53
-rw-r--r--source/blender/blenkernel/intern/object_deform.c3
-rw-r--r--source/blender/blenkernel/intern/particle_system.c10
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c8
-rw-r--r--source/blender/blenkernel/intern/sca.c44
-rw-r--r--source/blender/blenkernel/intern/scene.c19
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c2
-rw-r--r--source/blender/blenkernel/intern/text.c7
-rw-r--r--source/blender/blenkernel/intern/tracking.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c24
-rw-r--r--source/blender/blenlib/BLI_math_geom.h6
-rw-r--r--source/blender/blenlib/BLI_path_util.h5
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h4
-rw-r--r--source/blender/blenlib/BLI_string_utils.h63
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/math_geom.c48
-rw-r--r--source/blender/blenlib/intern/path_util.c159
-rw-r--r--source/blender/blenlib/intern/string_utf8.c18
-rw-r--r--source/blender/blenlib/intern/string_utils.c385
-rw-r--r--source/blender/blenloader/intern/readfile.c21
-rw-r--r--source/blender/blenloader/intern/readfile.h2
-rw-r--r--source/blender/blenloader/intern/versioning_260.c1
-rw-r--r--source/blender/blenloader/intern/versioning_270.c100
-rw-r--r--source/blender/blenloader/intern/writefile.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c34
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h7
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c142
-rw-r--r--source/blender/bmesh/operators/bmo_create.c6
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c10
-rw-r--r--source/blender/collada/AnimationImporter.cpp2
-rw-r--r--source/blender/collada/ArmatureExporter.cpp14
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp17
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.cpp19
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.h11
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc74
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc20
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc14
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc89
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h12
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc16
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc2
-rw-r--r--source/blender/editors/animation/anim_filter.c2
-rw-r--r--source/blender/editors/animation/keyframes_general.c3
-rw-r--r--source/blender/editors/armature/armature_add.c9
-rw-r--r--source/blender/editors/armature/armature_naming.c69
-rw-r--r--source/blender/editors/armature/armature_select.c23
-rw-r--r--source/blender/editors/armature/armature_skinning.c3
-rw-r--r--source/blender/editors/armature/armature_utils.c3
-rw-r--r--source/blender/editors/armature/pose_edit.c16
-rw-r--r--source/blender/editors/armature/pose_lib.c1
-rw-r--r--source/blender/editors/armature/pose_transform.c3
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt1
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c810
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h3
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c1145
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c7
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c28
-rw-r--r--source/blender/editors/include/ED_armature.h1
-rw-r--r--source/blender/editors/interface/interface.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c2
-rw-r--r--source/blender/editors/interface/interface_layout.c6
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c33
-rw-r--r--source/blender/editors/object/object_edit.c1
-rw-r--r--source/blender/editors/object/object_relations.c6
-rw-r--r--source/blender/editors/object/object_select.c3
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c3
-rw-r--r--source/blender/editors/space_action/action_draw.c34
-rw-r--r--source/blender/editors/space_logic/logic_ops.c1
-rw-r--r--source/blender/editors/space_logic/logic_window.c2
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c18
-rw-r--r--source/blender/editors/space_node/drawnode.c14
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c1
-rw-r--r--source/blender/editors/space_text/text_ops.c1
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c190
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c10
-rw-r--r--source/blender/editors/transform/transform.c4
-rw-r--r--source/blender/editors/transform/transform.h2
-rw-r--r--source/blender/editors/transform/transform_input.c4
-rw-r--r--source/blender/editors/transform/transform_orientations.c2
-rw-r--r--source/blender/editors/transform/transform_snap.c8
-rw-r--r--source/blender/editors/transform/transform_snap_object.c1178
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl6
-rw-r--r--source/blender/makesdna/DNA_action_types.h8
-rw-r--r--source/blender/makesdna/DNA_node_types.h1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h50
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_actuator.c3
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c29
-rw-r--r--source/blender/makesrna/intern/rna_controller.c1
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c25
-rw-r--r--source/blender/makesrna/intern/rna_key.c1
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c3
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c28
-rw-r--r--source/blender/makesrna/intern/rna_particle.c2
-rw-r--r--source/blender/makesrna/intern/rna_pose.c1
-rw-r--r--source/blender/makesrna/intern/rna_property.c1
-rw-r--r--source/blender/makesrna/intern/rna_scene.c127
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c9
-rw-r--r--source/blender/makesrna/intern/rna_sensor.c1
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c2
-rw-r--r--source/blender/modifiers/CMakeLists.txt4
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c2
-rw-r--r--source/blender/modifiers/intern/MOD_array.c8
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c2
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c2
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c12
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c2
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c11
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c4
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c15
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c2
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c2
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c2
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c2
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c2
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c2
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c4
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c2
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c18
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c7
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c4
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c4
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c8
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c6
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c6
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hueSatVal.c16
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_path.c2
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c2
-rw-r--r--source/blender/render/intern/source/pipeline.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c11
-rw-r--r--source/creator/creator_args.c2
m---------source/tools0
-rw-r--r--tests/gtests/CMakeLists.txt3
-rw-r--r--tests/gtests/blenlib/BLI_string_test.cc2
-rw-r--r--tests/gtests/testing/CMakeLists.txt3
-rw-r--r--tests/python/CMakeLists.txt40
-rwxr-xr-xtests/python/cycles_render_tests.py99
297 files changed, 6642 insertions, 3552 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d61a7de1a33..7b98fe4ad73 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -727,7 +727,7 @@ if(NOT WITH_BOOST)
macro(set_and_warn
_setting _val)
if(${${_setting}})
- message(STATUS "'WITH_BOOST' is disabled: forceing 'set(${_setting} ${_val})'")
+ message(STATUS "'WITH_BOOST' is disabled: forcing 'set(${_setting} ${_val})'")
endif()
set(${_setting} ${_val})
endmacro()
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index ecb1cf87511..c4d6b284c48 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -344,7 +344,7 @@ OSL_FORCE_REBUILD=false
OSL_SKIP=false
# OpenSubdiv needs to be compiled for now
-OSD_VERSION="3.1.0"
+OSD_VERSION="3.1.1"
OSD_VERSION_MIN=$OSD_VERSION
OSD_FORCE_BUILD=false
OSD_FORCE_REBUILD=false
diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake
index 96c06ef8eb5..0732e10133c 100644
--- a/build_files/cmake/Modules/GTestTesting.cmake
+++ b/build_files/cmake/Modules/GTestTesting.cmake
@@ -45,7 +45,7 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TESTS_OUTPUT_DIR}"
INCLUDE_DIRECTORIES "${TEST_INC}")
if(${DO_ADD_TEST})
- add_test(${NAME}_test ${TESTS_OUTPUT_DIR}/${NAME}_test)
+ add_test(NAME ${NAME}_test COMMAND ${TESTS_OUTPUT_DIR}/${NAME}_test WORKING_DIRECTORY $<TARGET_FILE_DIR:blender>)
endif()
endif()
endmacro()
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 2e3a1907063..09428953a46 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -416,14 +416,7 @@ function(setup_liblinks
target_link_libraries(${target} ${OPENCOLORIO_LIBRARIES})
endif()
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}")
- target_link_libraries_optimized(${target} "${OPENSUBDIV_LIBRARIES}")
- unset(OPENSUBDIV_LIBRARIES_DEBUG)
- else()
target_link_libraries(${target} ${OPENSUBDIV_LIBRARIES})
- endif()
endif()
if(WITH_OPENVDB)
target_link_libraries(${target} ${OPENVDB_LIBRARIES} ${TBB_LIBRARIES})
diff --git a/build_files/cmake/platform/platform_win32_msvc.cmake b/build_files/cmake/platform/platform_win32_msvc.cmake
index 3b50351a131..45a44596e61 100644
--- a/build_files/cmake/platform/platform_win32_msvc.cmake
+++ b/build_files/cmake/platform/platform_win32_msvc.cmake
@@ -446,10 +446,20 @@ if(WITH_MOD_CLOTH_ELTOPO)
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)
+ set(OPENSUBDIV_INCLUDE_DIR ${LIBDIR}/opensubdiv/include)
+ set(OPENSUBDIV_LIBPATH ${LIBDIR}/opensubdiv/lib)
+ set(OPENSUBDIV_LIBRARIES optimized ${OPENSUBDIV_LIBPATH}/osdCPU.lib
+ optimized ${OPENSUBDIV_LIBPATH}/osdGPU.lib
+ debug ${OPENSUBDIV_LIBPATH}/osdCPU_d.lib
+ debug ${OPENSUBDIV_LIBPATH}/osdGPU_d.lib
+ )
+ set(OPENSUBDIV_HAS_OPENMP TRUE)
+ set(OPENSUBDIV_HAS_TBB FALSE)
+ set(OPENSUBDIV_HAS_OPENCL TRUE)
+ set(OPENSUBDIV_HAS_CUDA FALSE)
+ set(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK TRUE)
+ set(OPENSUBDIV_HAS_GLSL_COMPUTE TRUE)
+ windows_find_package(OpenSubdiv)
endif()
if(WITH_SDL)
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 3cb98c677c1..ec3131ca19e 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -1632,13 +1632,9 @@ 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("import sys, os\n\n")
+ fw("extensions = ['sphinx.ext.intersphinx']\n\n")
+ fw("intersphinx_mapping = {'blender_manual': ('https://docs.blender.org/manual/en/dev/', None)}\n\n")
fw("project = 'Blender'\n")
# fw("master_doc = 'index'\n")
fw("copyright = u'Blender Foundation'\n")
@@ -1655,6 +1651,7 @@ def write_sphinx_conf_py(basepath):
# not helpful since the source is generated, adds to upload size.
fw("html_copy_source = False\n")
+ fw("html_show_sphinx = False\n")
fw("html_split_index = True\n")
fw("\n")
diff --git a/doc/python_api/sphinx_doc_update.py b/doc/python_api/sphinx_doc_update.py
index c7f0367a2a0..3d48c1145e1 100755
--- a/doc/python_api/sphinx_doc_update.py
+++ b/doc/python_api/sphinx_doc_update.py
@@ -41,9 +41,9 @@ import tempfile
import zipfile
-DEFAULT_RSYNC_SERVER = "www.blender.org"
+DEFAULT_RSYNC_SERVER = "docs.blender.org"
DEFAULT_RSYNC_ROOT = "/api/"
-DEFAULT_SYMLINK_ROOT = "/data/www/vhosts/www.blender.org/api"
+DEFAULT_SYMLINK_ROOT = "/data/www/vhosts/docs.blender.org/api"
def argparse_create():
diff --git a/extern/gflags/README.blender b/extern/gflags/README.blender
index 0c8ea9a2be3..b48d4d5d110 100644
--- a/extern/gflags/README.blender
+++ b/extern/gflags/README.blender
@@ -18,6 +18,8 @@ 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
+- Avoid attempt of acquiring mutex lock in FlagRegistry::GlobalRegistry when
doing static flags initialization. See d81dd2d in Blender repository.
+- Made `google::{anonymous}::FlagValue::ValueSize() const` inlined, so it does
+ not trigger strict compiler warning. \ No newline at end of file
diff --git a/extern/gflags/src/gflags.cc b/extern/gflags/src/gflags.cc
index 7abe1f70da3..6dcc5170bcc 100644
--- a/extern/gflags/src/gflags.cc
+++ b/extern/gflags/src/gflags.cc
@@ -218,7 +218,7 @@ class FlagValue {
bool Equal(const FlagValue& x) const;
FlagValue* New() const; // creates a new one with default value
void CopyFrom(const FlagValue& x);
- int ValueSize() const;
+ inline int ValueSize() const;
// Calls the given validate-fn on value_buffer_, and returns
// whatever it returns. But first casts validate_fn_proto to a
@@ -443,7 +443,7 @@ void FlagValue::CopyFrom(const FlagValue& x) {
}
}
-int FlagValue::ValueSize() const {
+inline int FlagValue::ValueSize() const {
if (type_ > FV_MAX_INDEX) {
assert(false); // unknown type
return 0;
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index ea7d1379390..29285c6ad68 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -74,7 +74,6 @@ elseif(CMAKE_COMPILER_IS_GNUCC)
if(CXX_HAS_AVX2)
set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c -mfpmath=sse")
endif()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
check_cxx_compiler_flag(-msse CXX_HAS_SSE)
check_cxx_compiler_flag(-mavx CXX_HAS_AVX)
@@ -90,7 +89,6 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if(CXX_HAS_AVX2)
set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c")
endif()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math")
endif()
if(CXX_HAS_SSE)
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 29a68bf272e..35a30ae683f 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -523,7 +523,7 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
/* we don't yet support arbitrary attributes, for now add vertex
* coordinates as generated coordinates if requested */
- if (mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) {
+ if(mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) {
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
memcpy(attr->data_float3(), mesh->verts.data(), sizeof(float3)*mesh->verts.size());
}
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 80841eb7eb3..4593f590b03 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -23,11 +23,25 @@ bl_info = {
"location": "Info header, render engine menu",
"description": "Cycles Render Engine integration",
"warning": "",
- "wiki_url": "https://www.blender.org/manual/render/cycles/index.html",
+ "wiki_url": "https://docs.blender.org/manual/en/dev/render/cycles/",
"tracker_url": "",
"support": 'OFFICIAL',
"category": "Render"}
+# Support 'reload' case.
+if "bpy" in locals():
+ import importlib
+ if "engine" in locals():
+ importlib.reload(engine)
+ if "version_update" in locals():
+ importlib.reload(version_update)
+ if "ui" in locals():
+ importlib.reload(ui)
+ if "properties" in locals():
+ importlib.reload(properties)
+ if "presets" in locals():
+ importlib.reload(presets)
+
import bpy
from . import (
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 8953fbc7dd1..69f728d2743 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -62,7 +62,7 @@ def _parse_command_line():
num_resumable_chunks = None
current_resumable_chunk = None
- # TODO(sergey): Add some nice error ptins if argument is not used properly.
+ # TODO(sergey): Add some nice error prints if argument is not used properly.
idx = 0
while idx < len(argv) - 1:
arg = argv[idx]
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index ad1ccb476ee..1e068566b43 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -528,6 +528,12 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Use special type BVH optimized for hair (uses more ram but renders faster)",
default=True,
)
+ cls.debug_bvh_time_steps = IntProperty(
+ name="BVH Time Steps",
+ description="Split BVH primitives by this number of time steps to speed up render time in cost of memory",
+ default=0,
+ min=0, max=16,
+ )
cls.tile_order = EnumProperty(
name="Tile Order",
description="Tile order for rendering",
@@ -632,6 +638,20 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
items=enum_texture_limit
)
+ cls.ao_bounces = IntProperty(
+ name="AO Bounces",
+ default=0,
+ description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature",
+ min=0, max=1024,
+ )
+
+ cls.ao_bounces_render = IntProperty(
+ name="AO Bounces Render",
+ default=0,
+ description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature",
+ min=0, max=1024,
+ )
+
# Various fine-tuning debug flags
def devices_update_callback(self, context):
@@ -1144,8 +1164,8 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
description="Cycles SceneRenderLayer Settings",
type=cls,
)
- cls.pass_debug_bvh_traversal_steps = BoolProperty(
- name="Debug BVH Traversal Steps",
+ cls.pass_debug_bvh_traversed_nodes = BoolProperty(
+ name="Debug BVH Traversed Nodes",
description="Store Debug BVH Traversal Steps pass",
default=False,
)
@@ -1159,6 +1179,11 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
description="Store Debug Ray Bounces pass",
default=False,
)
+ cls.pass_debug_bvh_intersections = BoolProperty(
+ name="Debug BVH Intersections",
+ description="Store Debug BVH Intersections pass",
+ default=False,
+ )
@classmethod
def unregister(cls):
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index d6463441ad8..74b61b02e33 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -217,7 +217,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
draw_samples_info(layout, context)
-class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel):
+class CyclesRender_PT_geometry(CyclesButtonsPanel, Panel):
bl_label = "Geometry"
bl_options = {'DEFAULT_CLOSED'}
@@ -226,6 +226,7 @@ class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel):
scene = context.scene
cscene = scene.cycles
+ ccscene = scene.cycles_curves
if cscene.feature_set == 'EXPERIMENTAL':
split = layout.split()
@@ -252,6 +253,25 @@ class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel):
row.prop(cscene, "volume_step_size")
row.prop(cscene, "volume_max_steps")
+ layout.prop(ccscene, "use_curves", text="Use Hair")
+ col = layout.column()
+ col.active = ccscene.use_curves
+
+ col.prop(ccscene, "primitive", text="Primitive")
+ col.prop(ccscene, "shape", text="Shape")
+
+ if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'):
+ col.prop(ccscene, "cull_backfacing", text="Cull back-faces")
+
+ if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK':
+ col.prop(ccscene, "resolution", text="Resolution")
+ elif ccscene.primitive == 'CURVE_SEGMENTS':
+ col.prop(ccscene, "subdivisions", text="Curve subdivisions")
+
+ row = col.row()
+ row.prop(ccscene, "minimum_width", text="Min Pixels")
+ row.prop(ccscene, "maximum_width", text="Max Ext.")
+
class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel):
bl_label = "Light Paths"
@@ -412,6 +432,10 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
col.prop(cscene, "debug_use_spatial_splits")
col.prop(cscene, "debug_use_hair_bvh")
+ row = col.row()
+ row.active = not cscene.debug_use_spatial_splits
+ row.prop(cscene, "debug_bvh_time_steps")
+
class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel):
bl_label = "Layer"
@@ -511,9 +535,10 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel):
if _cycles.with_cycles_debug:
col = layout.column()
- col.prop(crl, "pass_debug_bvh_traversal_steps")
+ col.prop(crl, "pass_debug_bvh_traversed_nodes")
col.prop(crl, "pass_debug_bvh_traversed_instances")
col.prop(crl, "pass_debug_ray_bounces")
+ col.prop(crl, "pass_debug_bvh_intersections")
class CyclesRender_PT_views(CyclesButtonsPanel, Panel):
@@ -814,10 +839,13 @@ class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel):
col = layout.column()
col.label(text="Performance:")
row = col.row()
- row.active = scene.render.use_simplify and cscene.use_camera_cull
- row.prop(cob, "use_camera_cull")
- row.active = scene.render.use_simplify and cscene.use_distance_cull
- row.prop(cob, "use_distance_cull")
+ sub = row.row()
+ sub.active = scene.render.use_simplify and cscene.use_camera_cull
+ sub.prop(cob, "use_camera_cull")
+
+ sub = row.row()
+ sub.active = scene.render.use_simplify and cscene.use_distance_cull
+ sub.prop(cob, "use_distance_cull")
class CYCLES_OT_use_shading_nodes(Operator):
@@ -1058,10 +1086,11 @@ class CyclesWorld_PT_ambient_occlusion(CyclesButtonsPanel, Panel):
layout = self.layout
light = context.world.light_settings
+ scene = context.scene
row = layout.row()
sub = row.row()
- sub.active = light.use_ambient_occlusion
+ sub.active = light.use_ambient_occlusion or scene.render.use_simplify
sub.prop(light, "ao_factor", text="Factor")
row.prop(light, "distance", text="Distance")
@@ -1438,43 +1467,6 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
layout.template_ID(slot, "texture", new="texture.new")
-class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
- bl_label = "Cycles Hair Rendering"
- bl_context = "particle"
-
- @classmethod
- def poll(cls, context):
- psys = context.particle_system
- return CyclesButtonsPanel.poll(context) and psys and psys.settings.type == 'HAIR'
-
- def draw_header(self, context):
- ccscene = context.scene.cycles_curves
- self.layout.prop(ccscene, "use_curves", text="")
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
- ccscene = scene.cycles_curves
-
- layout.active = ccscene.use_curves
-
- layout.prop(ccscene, "primitive", text="Primitive")
- layout.prop(ccscene, "shape", text="Shape")
-
- if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'):
- layout.prop(ccscene, "cull_backfacing", text="Cull back-faces")
-
- if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK':
- layout.prop(ccscene, "resolution", text="Resolution")
- elif ccscene.primitive == 'CURVE_SEGMENTS':
- layout.prop(ccscene, "subdivisions", text="Curve subdivisions")
-
- row = layout.row()
- row.prop(ccscene, "minimum_width", text="Min Pixels")
- row.prop(ccscene, "maximum_width", text="Max Ext.")
-
-
class CyclesRender_PT_bake(CyclesButtonsPanel, Panel):
bl_label = "Bake"
bl_context = "render"
@@ -1669,6 +1661,13 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
row.active = cscene.use_distance_cull
row.prop(cscene, "distance_cull_margin", text="Distance")
+ split = layout.split()
+ col = split.column()
+ col.prop(cscene, "ao_bounces")
+
+ col = split.column()
+ col.prop(cscene, "ao_bounces_render")
+
def draw_device(self, context):
scene = context.scene
layout = self.layout
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 378ae67f0c7..e42ff5d72a6 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -29,24 +29,6 @@
CCL_NAMESPACE_BEGIN
-/* Utilities */
-
-/* Hair curve functions */
-
-void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]);
-void interp_weights(float t, float data[4]);
-float shaperadius(float shape, float root, float tip, float time);
-void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData);
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num);
-bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num);
-bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background);
-void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData);
-void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
- float3 RotCam, bool is_ortho);
-void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution);
-void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata);
-void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata);
-
ParticleCurveData::ParticleCurveData()
{
}
@@ -55,7 +37,7 @@ ParticleCurveData::~ParticleCurveData()
{
}
-void interp_weights(float t, float data[4])
+static void interp_weights(float t, float data[4])
{
/* Cardinal curve interpolation */
float t2 = t * t;
@@ -68,17 +50,19 @@ void interp_weights(float t, float data[4])
data[3] = fc * t3 - fc * t2;
}
-void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4])
+static void curveinterp_v3_v3v3v3v3(float3 *p,
+ float3 *v1, float3 *v2, float3 *v3, float3 *v4,
+ const float w[4])
{
p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3];
p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3];
p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3];
}
-float shaperadius(float shape, float root, float tip, float time)
+static float shaperadius(float shape, float root, float tip, float time)
{
float radius = 1.0f - time;
-
+
if(shape != 0.0f) {
if(shape < 0.0f)
radius = powf(radius, 1.0f + shape);
@@ -90,7 +74,13 @@ float shaperadius(float shape, float root, float tip, float time)
/* curve functions */
-void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData)
+static void InterpolateKeySegments(int seg,
+ int segno,
+ int key,
+ int curve,
+ float3 *keyloc,
+ float *time,
+ ParticleCurveData *CData)
{
float3 ckey_loc1 = CData->curvekey_co[key];
float3 ckey_loc2 = ckey_loc1;
@@ -119,7 +109,11 @@ void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyl
curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
}
-bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
+static bool ObtainCacheParticleData(Mesh *mesh,
+ BL::Mesh *b_mesh,
+ BL::Object *b_ob,
+ ParticleCurveData *CData,
+ bool background)
{
int curvenum = 0;
int keyno = 0;
@@ -143,7 +137,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
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);
int totcurves = totchild;
-
+
if(b_part.child_type() == 0 || totchild == 0)
totcurves += totparts;
@@ -161,7 +155,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
CData->psys_shader.push_back_slow(shader);
float radius = get_float(cpsys, "radius_scale") * 0.5f;
-
+
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"));
@@ -181,7 +175,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_slow(keyno);
-
+
float curve_length = 0.0f;
float3 pcKey;
for(int step_no = 0; step_no < ren_step; step_no++) {
@@ -213,7 +207,12 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
return true;
}
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num)
+static bool ObtainCacheParticleUV(Mesh *mesh,
+ BL::Mesh *b_mesh,
+ BL::Object *b_ob,
+ ParticleCurveData *CData,
+ bool background,
+ int uv_num)
{
if(!(mesh && b_mesh && b_ob && CData))
return false;
@@ -231,7 +230,7 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti
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);
int totcurves = totchild;
-
+
if(b_part.child_type() == 0 || totchild == 0)
totcurves += totparts;
@@ -267,7 +266,12 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti
return true;
}
-bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num)
+static bool ObtainCacheParticleVcol(Mesh *mesh,
+ BL::Mesh *b_mesh,
+ BL::Object *b_ob,
+ ParticleCurveData *CData,
+ bool background,
+ int vcol_num)
{
if(!(mesh && b_mesh && b_ob && CData))
return false;
@@ -285,7 +289,7 @@ bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
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);
int totcurves = totchild;
-
+
if(b_part.child_type() == 0 || totchild == 0)
totcurves += totparts;
@@ -333,16 +337,16 @@ static void set_resolution(BL::Object *b_ob, BL::Scene *scene, bool render)
}
}
-void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
- float3 RotCam, bool is_ortho)
+static void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
+ float3 RotCam, bool is_ortho)
{
int vertexno = mesh->verts.size();
int vertexindex = vertexno;
int numverts = 0, numtris = 0;
/* compute and reserve size of arrays */
- for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
- for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+ for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
continue;
@@ -354,8 +358,8 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
/* actually export */
- for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
- for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+ for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
continue;
@@ -380,7 +384,7 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 1, CData->curve_firstkey[curve])];
- else
+ else
v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1];
time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
@@ -416,15 +420,17 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
/* texture coords still needed */
}
-void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution)
+static void ExportCurveTriangleGeometry(Mesh *mesh,
+ ParticleCurveData *CData,
+ int resolution)
{
int vertexno = mesh->verts.size();
int vertexindex = vertexno;
int numverts = 0, numtris = 0;
/* compute and reserve size of arrays */
- for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
- for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+ for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
continue;
@@ -436,8 +442,8 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol
mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
/* actually export */
- for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
- for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+ for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
continue;
@@ -548,7 +554,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol
/* texture coords still needed */
}
-void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
+static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
{
int num_keys = 0;
int num_curves = 0;
@@ -557,13 +563,13 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
return;
Attribute *attr_intercept = NULL;
-
+
if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
/* compute and reserve size of arrays */
- for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
- for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+ for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
continue;
@@ -582,8 +588,8 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
num_curves = 0;
/* actually export */
- for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
- for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+ for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
continue;
@@ -677,8 +683,13 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
/* in case of new attribute, we verify if there really was any motion */
if(new_attribute) {
if(i != numkeys || !have_motion) {
- /* no motion, remove attributes again */
- VLOG(1) << "No motion, removing attribute";
+ /* No motion or hair "topology" changed, remove attributes again. */
+ if(i != numkeys) {
+ VLOG(1) << "Hair topology changed, removing attribute.";
+ }
+ else {
+ VLOG(1) << "No motion, removing attribute.";
+ }
mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
}
else if(time_index > 0) {
@@ -698,7 +709,10 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
}
}
-void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata)
+static void ExportCurveTriangleUV(ParticleCurveData *CData,
+ int vert_offset,
+ int resol,
+ float3 *uvdata)
{
if(uvdata == NULL)
return;
@@ -708,8 +722,8 @@ void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol,
int vertexindex = vert_offset;
- for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
- for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+ for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
continue;
@@ -743,15 +757,18 @@ void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol,
}
}
-void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata)
+static void ExportCurveTriangleVcol(ParticleCurveData *CData,
+ int vert_offset,
+ int resol,
+ uchar4 *cdata)
{
if(cdata == NULL)
return;
int vertexindex = vert_offset;
- for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
- for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+ for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
continue;
@@ -1044,4 +1061,3 @@ void BlenderSync::sync_curves(Mesh *mesh,
}
CCL_NAMESPACE_END
-
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 66893d4d668..85117cfff7b 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -927,6 +927,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
+ /* Disable adaptive subdivision while baking as the baking system
+ * currently doesnt support the topology and will crash.
+ */
+ if(scene->bake_manager->get_baking()) {
+ mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
+ }
+
BL::Mesh b_mesh = object_to_mesh(b_data,
b_ob,
b_scene,
diff --git a/intern/cycles/blender/blender_object_cull.cpp b/intern/cycles/blender/blender_object_cull.cpp
index b8582df0f93..08918dd1a49 100644
--- a/intern/cycles/blender/blender_object_cull.cpp
+++ b/intern/cycles/blender/blender_object_cull.cpp
@@ -43,7 +43,7 @@ BlenderObjectCulling::BlenderObjectCulling(Scene *scene, BL::Scene& b_scene)
camera_cull_margin_ = get_float(cscene, "camera_cull_margin");
distance_cull_margin_ = get_float(cscene, "distance_cull_margin");
- if (distance_cull_margin_ == 0.0f) {
+ if(distance_cull_margin_ == 0.0f) {
use_scene_distance_cull_ = false;
}
}
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index f3df744fcc1..9f95c4d3015 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -1318,6 +1318,9 @@ void BlenderSession::update_resumable_tile_manager(int num_samples)
VLOG(1) << "Samples range start is " << range_start_sample << ", "
<< "number of samples to render is " << range_num_samples;
+ scene->integrator->start_sample = range_start_sample;
+ scene->integrator->tag_update(scene);
+
session->tile_manager.range_start_sample = range_start_sample;
session->tile_manager.range_num_samples = range_num_samples;
}
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index f63f94ab37a..f6ec015e1b8 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -640,7 +640,8 @@ static ShaderNode *add_node(Scene *scene,
image->filename.string(),
image->builtin_data,
get_image_interpolation(b_image_node),
- get_image_extension(b_image_node));
+ get_image_extension(b_image_node),
+ image->use_alpha);
}
}
image->color_space = (NodeImageColorSpace)b_image_node.color_space();
@@ -686,7 +687,8 @@ static ShaderNode *add_node(Scene *scene,
env->filename.string(),
env->builtin_data,
get_image_interpolation(b_env_node),
- EXTENSION_REPEAT);
+ EXTENSION_REPEAT,
+ env->use_alpha);
}
}
env->color_space = (NodeImageColorSpace)b_env_node.color_space();
@@ -823,7 +825,8 @@ static ShaderNode *add_node(Scene *scene,
point_density->filename.string(),
point_density->builtin_data,
point_density->interpolation,
- EXTENSION_CLIP);
+ EXTENSION_CLIP,
+ true);
}
node = point_density;
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index a232f7d3047..093870eebb0 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -322,6 +322,15 @@ void BlenderSync::sync_integrator()
integrator->volume_samples = volume_samples;
}
+ if(b_scene.render().use_simplify()) {
+ if(preview) {
+ integrator->ao_bounces = get_int(cscene, "ao_bounces");
+ }
+ else {
+ integrator->ao_bounces = get_int(cscene, "ao_bounces_render");
+ }
+ }
+
if(integrator->modified(previntegrator))
integrator->tag_update(scene);
}
@@ -507,8 +516,9 @@ PassType BlenderSync::get_pass_type(BL::RenderPass& b_pass)
MAP_PASS("Shadow", PASS_SHADOW);
#ifdef __KERNEL_DEBUG__
- MAP_PASS("Debug BVH Traversal Steps", PASS_BVH_TRAVERSAL_STEPS);
+ MAP_PASS("Debug BVH Traversed Nodes", PASS_BVH_TRAVERSED_NODES);
MAP_PASS("Debug BVH Traversed Instances", PASS_BVH_TRAVERSED_INSTANCES);
+ MAP_PASS("Debug BVH Intersections", PASS_BVH_INTERSECTIONS);
MAP_PASS("Debug Ray Bounces", PASS_RAY_BOUNCES);
#endif
@@ -560,9 +570,9 @@ array<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
#ifdef __KERNEL_DEBUG__
PointerRNA crp = RNA_pointer_get(&b_srlay.ptr, "cycles");
- if(get_boolean(crp, "pass_debug_bvh_traversal_steps")) {
- ADD_PASS(1, "Debug BVH Traversal Steps", "X");
- Pass::add(PASS_BVH_TRAVERSAL_STEPS, passes);
+ if(get_boolean(crp, "pass_debug_bvh_traversed_nodes")) {
+ ADD_PASS(1, "Debug BVH Traversed Nodes", "X");
+ Pass::add(PASS_BVH_TRAVERSED_NODES, passes);
}
if(get_boolean(crp, "pass_debug_bvh_traversed_instances")) {
ADD_PASS(1, "Debug BVH Traversed Instances", "X");
@@ -572,6 +582,10 @@ array<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
ADD_PASS(1, "Debug Ray Bounces", "X");
Pass::add(PASS_RAY_BOUNCES, passes);
}
+ if(get_boolean(crp, "pass_debug_bvh_intersections")) {
+ ADD_PASS(1, "Debug BVH Intersections", "X");
+ Pass::add(PASS_BVH_INTERSECTIONS, passes);
+ }
#endif
if(b_srlay.keep_denoise_data()) {
@@ -627,6 +641,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene,
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");
+ params.num_bvh_time_steps = RNA_int_get(&cscene, "debug_bvh_time_steps");
if(background && params.shadingsystem != SHADINGSYSTEM_OSL)
params.persistent_data = r.use_persistent_data();
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index 4851de5b481..874a4246d1d 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -845,6 +845,8 @@ void QBVH::pack_aligned_inner(const BVHStackEntry& e,
bounds,
child,
e.node->m_visibility,
+ e.node->m_time_from,
+ e.node->m_time_to,
num);
}
@@ -852,12 +854,17 @@ void QBVH::pack_aligned_node(int idx,
const BoundBox *bounds,
const int *child,
const uint visibility,
+ const float time_from,
+ const float time_to,
const int num)
{
float4 data[BVH_QNODE_SIZE];
memset(data, 0, sizeof(data));
data[0].x = __uint_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED);
+ data[0].y = time_from;
+ data[0].z = time_to;
+
for(int i = 0; i < num; i++) {
float3 bb_min = bounds[i].min;
float3 bb_max = bounds[i].max;
@@ -908,6 +915,8 @@ void QBVH::pack_unaligned_inner(const BVHStackEntry& e,
bounds,
child,
e.node->m_visibility,
+ e.node->m_time_from,
+ e.node->m_time_to,
num);
}
@@ -916,12 +925,16 @@ void QBVH::pack_unaligned_node(int idx,
const BoundBox *bounds,
const int *child,
const uint visibility,
+ const float time_from,
+ const float time_to,
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);
+ data[0].y = time_from;
+ data[0].z = time_to;
for(int i = 0; i < num; i++) {
Transform space = BVHUnaligned::compute_node_transform(
@@ -1207,6 +1220,8 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
child_bbox,
&c[0],
visibility,
+ 0.0f,
+ 1.0f,
4);
}
else {
@@ -1214,6 +1229,8 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
child_bbox,
&c[0],
visibility,
+ 0.0f,
+ 1.0f,
4);
}
}
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index f8fb3b568ca..35f4d305883 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -175,6 +175,8 @@ protected:
const BoundBox *bounds,
const int *child,
const uint visibility,
+ const float time_from,
+ const float time_to,
const int num);
void pack_unaligned_inner(const BVHStackEntry& e,
@@ -185,6 +187,8 @@ protected:
const BoundBox *bounds,
const int *child,
const uint visibility,
+ const float time_from,
+ const float time_to,
const int num);
/* refit */
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index 14f66aca70f..a2f8b33cb0b 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -26,6 +26,7 @@
#include "scene.h"
#include "curves.h"
+#include "util_algorithm.h"
#include "util_debug.h"
#include "util_foreach.h"
#include "util_logging.h"
@@ -112,81 +113,237 @@ BVHBuild::~BVHBuild()
/* Adding References */
-void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i)
+void BVHBuild::add_reference_triangles(BoundBox& root, BoundBox& center, Mesh *mesh, int i)
{
- if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
- Attribute *attr_mP = NULL;
-
- 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);
+ const Attribute *attr_mP = NULL;
+ if(mesh->has_motion_blur()) {
+ attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+ const size_t num_triangles = mesh->num_triangles();
+ for(uint j = 0; j < num_triangles; j++) {
+ Mesh::Triangle t = mesh->get_triangle(j);
+ const float3 *verts = &mesh->verts[0];
+ if(attr_mP == NULL) {
BoundBox bounds = BoundBox::empty;
- PrimitiveType type = PRIMITIVE_TRIANGLE;
-
- 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();
-
- for(size_t i = 0; i < steps; i++)
- t.bounds_grow(vert_steps + i*mesh_size, bounds);
-
- type = PRIMITIVE_MOTION_TRIANGLE;
+ t.bounds_grow(verts, bounds);
+ if(bounds.valid()) {
+ references.push_back(BVHReference(bounds,
+ j,
+ i,
+ PRIMITIVE_TRIANGLE));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ else if(params.num_motion_triangle_steps == 0 || params.use_spatial_split) {
+ /* Motion triangles, simple case: single node for the whole
+ * primitive. Lowest memory footprint and faster BVH build but
+ * least optimal ray-tracing.
+ */
+ /* TODO(sergey): Support motion steps for spatially split BVH. */
+ const size_t num_verts = mesh->verts.size();
+ const size_t num_steps = mesh->motion_steps;
+ const float3 *vert_steps = attr_mP->data_float3();
+ BoundBox bounds = BoundBox::empty;
+ t.bounds_grow(verts, bounds);
+ for(size_t step = 0; step < num_steps - 1; step++) {
+ t.bounds_grow(vert_steps + step*num_verts, bounds);
}
-
if(bounds.valid()) {
- references.push_back(BVHReference(bounds, j, i, type));
+ references.push_back(
+ BVHReference(bounds,
+ j,
+ i,
+ PRIMITIVE_MOTION_TRIANGLE));
root.grow(bounds);
center.grow(bounds.center2());
}
}
+ else {
+ /* Motion triangles, trace optimized case: we split triangle
+ * primitives into separate nodes for each of the time steps.
+ * This way we minimize overlap of neighbor curve primitives.
+ */
+ const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
+ const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
+ const size_t num_verts = mesh->verts.size();
+ const size_t num_steps = mesh->motion_steps;
+ const float3 *vert_steps = attr_mP->data_float3();
+ /* Calculate bounding box of the previous time step.
+ * Will be reused later to avoid duplicated work on
+ * calculating BVH time step boundbox.
+ */
+ float3 prev_verts[3];
+ t.motion_verts(verts,
+ vert_steps,
+ num_verts,
+ num_steps,
+ 0.0f,
+ prev_verts);
+ BoundBox prev_bounds = BoundBox::empty;
+ prev_bounds.grow(prev_verts[0]);
+ prev_bounds.grow(prev_verts[1]);
+ prev_bounds.grow(prev_verts[2]);
+ /* Create all primitive time steps, */
+ for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
+ const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1;
+ float3 curr_verts[3];
+ t.motion_verts(verts,
+ vert_steps,
+ num_verts,
+ num_steps,
+ curr_time,
+ curr_verts);
+ BoundBox curr_bounds = BoundBox::empty;
+ curr_bounds.grow(curr_verts[0]);
+ curr_bounds.grow(curr_verts[1]);
+ curr_bounds.grow(curr_verts[2]);
+ BoundBox bounds = prev_bounds;
+ bounds.grow(curr_bounds);
+ if(bounds.valid()) {
+ const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
+ references.push_back(
+ BVHReference(bounds,
+ j,
+ i,
+ PRIMITIVE_MOTION_TRIANGLE,
+ prev_time,
+ curr_time));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ /* Current time boundbox becomes previous one for the
+ * next time step.
+ */
+ prev_bounds = curr_bounds;
+ }
+ }
}
+}
- 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);
-
- 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++) {
+void BVHBuild::add_reference_curves(BoundBox& root, BoundBox& center, Mesh *mesh, int i)
+{
+ const Attribute *curve_attr_mP = NULL;
+ if(mesh->has_motion_blur()) {
+ curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+ const size_t num_curves = mesh->num_curves();
+ for(uint j = 0; j < num_curves; j++) {
+ const Mesh::Curve curve = mesh->get_curve(j);
+ const float *curve_radius = &mesh->curve_radius[0];
+ for(int k = 0; k < curve.num_keys - 1; k++) {
+ if(curve_attr_mP == NULL) {
+ /* Really simple logic for static hair. */
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;
- 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, &mesh->curve_radius[0], bounds);
-
- type = PRIMITIVE_MOTION_CURVE;
- }
-
+ curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds);
if(bounds.valid()) {
- int packed_type = PRIMITIVE_PACK_SEGMENT(type, k);
-
+ int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE, k);
references.push_back(BVHReference(bounds, j, i, packed_type));
root.grow(bounds);
center.grow(bounds.center2());
}
}
+ else if(params.num_motion_curve_steps == 0 || params.use_spatial_split) {
+ /* Simple case of motion curves: single node for the while
+ * shutter time. Lowest memory usage but less optimal
+ * rendering.
+ */
+ /* TODO(sergey): Support motion steps for spatially split BVH. */
+ BoundBox bounds = BoundBox::empty;
+ curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds);
+ const size_t num_keys = mesh->curve_keys.size();
+ const size_t num_steps = mesh->motion_steps;
+ const float3 *key_steps = curve_attr_mP->data_float3();
+ for(size_t step = 0; step < num_steps - 1; step++) {
+ curve.bounds_grow(k,
+ key_steps + step*num_keys,
+ curve_radius,
+ bounds);
+ }
+ if(bounds.valid()) {
+ int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k);
+ references.push_back(BVHReference(bounds,
+ j,
+ i,
+ packed_type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ else {
+ /* Motion curves, trace optimized case: we split curve keys
+ * primitives into separate nodes for each of the time steps.
+ * This way we minimize overlap of neighbor curve primitives.
+ */
+ const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
+ const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
+ const size_t num_steps = mesh->motion_steps;
+ const float3 *curve_keys = &mesh->curve_keys[0];
+ const float3 *key_steps = curve_attr_mP->data_float3();
+ const size_t num_keys = mesh->curve_keys.size();
+ /* Calculate bounding box of the previous time step.
+ * Will be reused later to avoid duplicated work on
+ * calculating BVH time step boundbox.
+ */
+ float4 prev_keys[4];
+ curve.cardinal_motion_keys(curve_keys,
+ curve_radius,
+ key_steps,
+ num_keys,
+ num_steps,
+ 0.0f,
+ k - 1, k, k + 1, k + 2,
+ prev_keys);
+ BoundBox prev_bounds = BoundBox::empty;
+ curve.bounds_grow(prev_keys, prev_bounds);
+ /* Create all primitive time steps, */
+ for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
+ const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1;
+ float4 curr_keys[4];
+ curve.cardinal_motion_keys(curve_keys,
+ curve_radius,
+ key_steps,
+ num_keys,
+ num_steps,
+ curr_time,
+ k - 1, k, k + 1, k + 2,
+ curr_keys);
+ BoundBox curr_bounds = BoundBox::empty;
+ curve.bounds_grow(curr_keys, curr_bounds);
+ BoundBox bounds = prev_bounds;
+ bounds.grow(curr_bounds);
+ if(bounds.valid()) {
+ const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
+ int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k);
+ references.push_back(BVHReference(bounds,
+ j,
+ i,
+ packed_type,
+ prev_time,
+ curr_time));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ /* Current time boundbox becomes previous one for the
+ * next time step.
+ */
+ prev_bounds = curr_bounds;
+ }
+ }
}
}
}
+void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i)
+{
+ if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ add_reference_triangles(root, center, mesh, i);
+ }
+ if(params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ add_reference_curves(root, center, mesh, i);
+ }
+}
+
void BVHBuild::add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i)
{
references.push_back(BVHReference(ob->bounds, -1, i, 0));
@@ -200,7 +357,7 @@ static size_t count_curve_segments(Mesh *mesh)
for(size_t i = 0; i < num_curves; i++)
num += mesh->get_curve(i).num_keys - 1;
-
+
return num;
}
@@ -344,6 +501,7 @@ BVHNode* BVHBuild::run()
else {
/*rotate(rootnode, 4, 5);*/
rootnode->update_visibility();
+ rootnode->update_time();
}
if(rootnode != NULL) {
VLOG(1) << "BVH build statistics:\n"
@@ -371,7 +529,7 @@ void BVHBuild::progress_update()
{
if(time_dt() - progress_start_time < 0.25)
return;
-
+
double progress_start = (double)progress_count/(double)progress_total;
double duplicates = (double)(progress_total - progress_original_total)/(double)progress_total;
@@ -379,7 +537,7 @@ void BVHBuild::progress_update()
progress_start * 100.0, duplicates * 100.0);
progress.set_substatus(msg);
- progress_start_time = time_dt();
+ progress_start_time = time_dt();
}
void BVHBuild::thread_build_node(InnerNode *inner,
@@ -435,6 +593,7 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange& range,
return false;
size_t num_triangles = 0;
+ size_t num_motion_triangles = 0;
size_t num_curves = 0;
size_t num_motion_curves = 0;
@@ -445,13 +604,16 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange& range,
num_curves++;
if(ref.prim_type() & PRIMITIVE_MOTION_CURVE)
num_motion_curves++;
- else if(ref.prim_type() & PRIMITIVE_ALL_TRIANGLE)
+ else if(ref.prim_type() & PRIMITIVE_TRIANGLE)
num_triangles++;
+ else if(ref.prim_type() & PRIMITIVE_MOTION_TRIANGLE)
+ num_motion_triangles++;
}
- return (num_triangles < params.max_triangle_leaf_size) &&
- (num_curves < params.max_curve_leaf_size) &&
- (num_motion_curves < params.max_curve_leaf_size);
+ return (num_triangles <= params.max_triangle_leaf_size) &&
+ (num_motion_triangles <= params.max_motion_triangle_leaf_size) &&
+ (num_curves <= params.max_curve_leaf_size) &&
+ (num_motion_curves <= params.max_motion_curve_leaf_size);
}
/* multithreaded binning builder */
@@ -689,18 +851,24 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start,
prim_object[start] = ref->prim_object();
uint visibility = objects[ref->prim_object()]->visibility;
- return new LeafNode(ref->bounds(), visibility, start, start+1);
+ BVHNode *leaf_node = new LeafNode(ref->bounds(), visibility, start, start+1);
+ leaf_node->m_time_from = ref->time_from();
+ leaf_node->m_time_to = ref->time_to();
+ return leaf_node;
}
else {
int mid = num/2;
- BVHNode *leaf0 = create_object_leaf_nodes(ref, start, mid);
- BVHNode *leaf1 = create_object_leaf_nodes(ref+mid, start+mid, num-mid);
+ BVHNode *leaf0 = create_object_leaf_nodes(ref, start, mid);
+ BVHNode *leaf1 = create_object_leaf_nodes(ref+mid, start+mid, num-mid);
BoundBox bounds = BoundBox::empty;
bounds.grow(leaf0->m_bounds);
bounds.grow(leaf1->m_bounds);
- return new InnerNode(bounds, leaf0, leaf1);
+ BVHNode *inner_node = new InnerNode(bounds, leaf0, leaf1);
+ inner_node->m_time_from = min(leaf0->m_time_from, leaf1->m_time_from);
+ inner_node->m_time_to = max(leaf0->m_time_to, leaf1->m_time_to);
+ return inner_node;
}
}
@@ -804,6 +972,16 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
visibility[i],
start_index,
start_index + num);
+ if(true) {
+ float time_from = 1.0f, time_to = 0.0f;
+ for(int j = 0; j < num; ++j) {
+ const BVHReference &ref = p_ref[i][j];
+ time_from = min(time_from, ref.time_from());
+ time_to = max(time_to, ref.time_to());
+ }
+ leaf_node->m_time_from = time_from;
+ leaf_node->m_time_to = time_to;
+ }
if(alignment_found) {
/* Need to recalculate leaf bounds with new alignment. */
leaf_node->m_bounds = BoundBox::empty;
@@ -918,7 +1096,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
BVHNode *inner = new InnerNode(inner_bounds, leaves[1], leaves[2]);
return new InnerNode(range.bounds(), leaves[0], inner);
} else {
- /* Shpuld be doing more branches if more primitive types added. */
+ /* Should be doing more branches if more primitive types added. */
assert(num_leaves <= 5);
BoundBox inner_bounds_a = merge(leaves[0]->m_bounds, leaves[1]->m_bounds);
BoundBox inner_bounds_b = merge(leaves[2]->m_bounds, leaves[3]->m_bounds);
@@ -951,7 +1129,7 @@ void BVHBuild::rotate(BVHNode *node, int max_depth)
/* nothing to rotate if we reached a leaf node. */
if(node->is_leaf() || max_depth < 0)
return;
-
+
InnerNode *parent = (InnerNode*)node;
/* rotate all children first */
diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h
index 64180349935..ee3cde66a2f 100644
--- a/intern/cycles/bvh/bvh_build.h
+++ b/intern/cycles/bvh/bvh_build.h
@@ -63,6 +63,8 @@ protected:
friend class BVHObjectBinning;
/* Adding references. */
+ void add_reference_triangles(BoundBox& root, BoundBox& center, Mesh *mesh, int i);
+ void add_reference_curves(BoundBox& root, BoundBox& center, Mesh *mesh, int i);
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);
diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp
index f5cd699bdf4..67580e1bc7b 100644
--- a/intern/cycles/bvh/bvh_node.cpp
+++ b/intern/cycles/bvh/bvh_node.cpp
@@ -176,6 +176,19 @@ uint BVHNode::update_visibility()
return m_visibility;
}
+void BVHNode::update_time()
+{
+ if(!is_leaf()) {
+ InnerNode *inner = (InnerNode*)this;
+ BVHNode *child0 = inner->children[0];
+ BVHNode *child1 = inner->children[1];
+ child0->update_time();
+ child1->update_time();
+ m_time_from = min(child0->m_time_from, child1->m_time_from);
+ m_time_to = max(child0->m_time_to, child1->m_time_to);
+ }
+}
+
/* Inner Node */
void InnerNode::print(int depth) const
diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h
index 2faa40ab657..090c426de56 100644
--- a/intern/cycles/bvh/bvh_node.h
+++ b/intern/cycles/bvh/bvh_node.h
@@ -47,7 +47,9 @@ class BVHNode
{
public:
BVHNode() : m_is_unaligned(false),
- m_aligned_space(NULL)
+ m_aligned_space(NULL),
+ m_time_from(0.0f),
+ m_time_to(1.0f)
{
}
@@ -91,12 +93,15 @@ public:
void deleteSubtree();
uint update_visibility();
+ void update_time();
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;
+
+ float m_time_from, m_time_to;
};
class InnerNode : public BVHNode
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index 2e698a80742..65f9da1c194 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -43,7 +43,9 @@ public:
/* number of primitives in leaf */
int min_leaf_size;
int max_triangle_leaf_size;
+ int max_motion_triangle_leaf_size;
int max_curve_leaf_size;
+ int max_motion_curve_leaf_size;
/* object or mesh level bvh */
bool top_level;
@@ -59,6 +61,17 @@ public:
*/
bool use_unaligned_nodes;
+ /* Split time range to this number of steps and create leaf node for each
+ * of this time steps.
+ *
+ * Speeds up rendering of motion curve primitives in the cost of higher
+ * memory usage.
+ */
+ int num_motion_curve_steps;
+
+ /* Same as above, but for triangle primitives. */
+ int num_motion_triangle_steps;
+
/* fixed parameters */
enum {
MAX_DEPTH = 64,
@@ -80,13 +93,17 @@ public:
min_leaf_size = 1;
max_triangle_leaf_size = 8;
- max_curve_leaf_size = 2;
+ max_motion_triangle_leaf_size = 8;
+ max_curve_leaf_size = 1;
+ max_motion_curve_leaf_size = 4;
top_level = false;
use_qbvh = false;
use_unaligned_nodes = false;
primitive_mask = PRIMITIVE_ALL;
+
+ num_motion_curve_steps = 0;
}
/* SAH costs */
@@ -113,8 +130,15 @@ class BVHReference
public:
__forceinline BVHReference() {}
- __forceinline BVHReference(const BoundBox& bounds_, int prim_index_, int prim_object_, int prim_type)
- : rbounds(bounds_)
+ __forceinline BVHReference(const BoundBox& bounds_,
+ int prim_index_,
+ int prim_object_,
+ int prim_type,
+ float time_from = 0.0f,
+ float time_to = 1.0f)
+ : rbounds(bounds_),
+ time_from_(time_from),
+ time_to_(time_to)
{
rbounds.min.w = __int_as_float(prim_index_);
rbounds.max.w = __int_as_float(prim_object_);
@@ -125,6 +149,9 @@ public:
__forceinline int prim_index() const { return __float_as_int(rbounds.min.w); }
__forceinline int prim_object() const { return __float_as_int(rbounds.max.w); }
__forceinline int prim_type() const { return type; }
+ __forceinline float time_from() const { return time_from_; }
+ __forceinline float time_to() const { return time_to_; }
+
BVHReference& operator=(const BVHReference &arg) {
if(&arg != this) {
@@ -133,9 +160,11 @@ public:
return *this;
}
+
protected:
BoundBox rbounds;
uint type;
+ float time_from_, time_to_;
};
/* BVH Range
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index 11f312e5d17..b7fe34d8cbd 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -131,7 +131,7 @@ public:
{
if(first_error) {
fprintf(stderr, "\nRefer to the Cycles GPU rendering documentation for possible solutions:\n");
- fprintf(stderr, "http://www.blender.org/manual/render/cycles/gpu_rendering.html\n\n");
+ fprintf(stderr, "https://docs.blender.org/manual/en/dev/render/cycles/gpu_rendering.html\n\n");
first_error = false;
}
}
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index b3442fd0f90..27f81a0c428 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -169,6 +169,8 @@ set(SRC_GEOM_HEADERS
geom/geom_curve.h
geom/geom_motion_curve.h
geom/geom_motion_triangle.h
+ geom/geom_motion_triangle_intersect.h
+ geom/geom_motion_triangle_shader.h
geom/geom_object.h
geom/geom_patch.h
geom/geom_primitive.h
diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h
index 294362ea995..df33a86bb18 100644
--- a/intern/cycles/kernel/bvh/bvh_shadow_all.h
+++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h
@@ -187,7 +187,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* primitive intersection */
while(prim_addr < prim_addr2) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type);
bool hit;
@@ -222,6 +222,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_HAIR)
case PRIMITIVE_CURVE:
case PRIMITIVE_MOTION_CURVE: {
+ const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr);
if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
hit = bvh_cardinal_curve_intersect(kg,
isect_array,
@@ -231,7 +232,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
object,
prim_addr,
ray->time,
- type,
+ curve_type,
NULL,
0, 0);
}
@@ -244,7 +245,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
object,
prim_addr,
ray->time,
- type,
+ curve_type,
NULL,
0, 0);
}
diff --git a/intern/cycles/kernel/bvh/bvh_subsurface.h b/intern/cycles/kernel/bvh/bvh_subsurface.h
index d9623c94b2e..889bbca21e2 100644
--- a/intern/cycles/kernel/bvh/bvh_subsurface.h
+++ b/intern/cycles/kernel/bvh/bvh_subsurface.h
@@ -72,7 +72,7 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
ss_isect->num_hits = 0;
const int object_flag = kernel_tex_fetch(__object_flag, subsurface_object);
- if(!(object_flag & SD_TRANSFORM_APPLIED)) {
+ if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
#if BVH_FEATURE(BVH_MOTION)
Transform ob_itfm;
bvh_instance_motion_push(kg,
diff --git a/intern/cycles/kernel/bvh/bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h
index a0e478e972b..80c8f31473a 100644
--- a/intern/cycles/kernel/bvh/bvh_traversal.h
+++ b/intern/cycles/kernel/bvh/bvh_traversal.h
@@ -213,7 +213,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
--stack_ptr;
}
}
- BVH_DEBUG_NEXT_STEP();
+ BVH_DEBUG_NEXT_NODE();
}
/* if node is leaf, fetch triangle list */
@@ -235,7 +235,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
for(; prim_addr < prim_addr2; prim_addr++) {
- BVH_DEBUG_NEXT_STEP();
+ BVH_DEBUG_NEXT_INTERSECTION();
kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
if(triangle_intersect(kg,
&isect_precalc,
@@ -264,7 +264,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
for(; prim_addr < prim_addr2; prim_addr++) {
- BVH_DEBUG_NEXT_STEP();
+ BVH_DEBUG_NEXT_INTERSECTION();
kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
if(motion_triangle_intersect(kg,
isect,
@@ -296,8 +296,9 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
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);
+ BVH_DEBUG_NEXT_INTERSECTION();
+ const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr);
+ kernel_assert((curve_type & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL));
bool hit;
if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
hit = bvh_cardinal_curve_intersect(kg,
@@ -308,7 +309,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
object,
prim_addr,
ray->time,
- type,
+ curve_type,
lcg_state,
difl,
extmax);
@@ -322,7 +323,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
object,
prim_addr,
ray->time,
- type,
+ curve_type,
lcg_state,
difl,
extmax);
diff --git a/intern/cycles/kernel/bvh/bvh_types.h b/intern/cycles/kernel/bvh/bvh_types.h
index c3abe2e157d..ead424aaaaf 100644
--- a/intern/cycles/kernel/bvh/bvh_types.h
+++ b/intern/cycles/kernel/bvh/bvh_types.h
@@ -50,12 +50,17 @@ CCL_NAMESPACE_BEGIN
#ifdef __KERNEL_DEBUG__
# define BVH_DEBUG_INIT() \
do { \
- isect->num_traversal_steps = 0; \
+ isect->num_traversed_nodes = 0; \
isect->num_traversed_instances = 0; \
+ isect->num_intersections = 0; \
} while(0)
-# define BVH_DEBUG_NEXT_STEP() \
+# define BVH_DEBUG_NEXT_NODE() \
do { \
- ++isect->num_traversal_steps; \
+ ++isect->num_traversed_nodes; \
+ } while(0)
+# define BVH_DEBUG_NEXT_INTERSECTION() \
+ do { \
+ ++isect->num_intersections; \
} while(0)
# define BVH_DEBUG_NEXT_INSTANCE() \
do { \
@@ -63,7 +68,8 @@ CCL_NAMESPACE_BEGIN
} while(0)
#else /* __KERNEL_DEBUG__ */
# define BVH_DEBUG_INIT()
-# define BVH_DEBUG_NEXT_STEP()
+# define BVH_DEBUG_NEXT_NODE()
+# define BVH_DEBUG_NEXT_INTERSECTION()
# define BVH_DEBUG_NEXT_INSTANCE()
#endif /* __KERNEL_DEBUG__ */
diff --git a/intern/cycles/kernel/bvh/bvh_volume.h b/intern/cycles/kernel/bvh/bvh_volume.h
index 107373c17dc..57e5b8d736d 100644
--- a/intern/cycles/kernel/bvh/bvh_volume.h
+++ b/intern/cycles/kernel/bvh/bvh_volume.h
@@ -236,9 +236,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* instance push */
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) {
-
# if BVH_FEATURE(BVH_MOTION)
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
# else
diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h
index 529848ebe7b..5a1accebaa0 100644
--- a/intern/cycles/kernel/bvh/bvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/bvh_volume_all.h
@@ -287,7 +287,6 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* instance push */
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) {
# if BVH_FEATURE(BVH_MOTION)
diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
index 5f4d06f12ea..607295f9ed5 100644
--- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h
+++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
@@ -106,14 +106,20 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ if(false
#ifdef __VISIBILITY_FLAG__
- if((__float_as_uint(inodes.x) & PATH_RAY_SHADOW) == 0) {
+ || ((__float_as_uint(inodes.x) & PATH_RAY_SHADOW) == 0)
+#endif
+#if BVH_FEATURE(BVH_MOTION)
+ || UNLIKELY(ray->time < inodes.y)
+ || UNLIKELY(ray->time > inodes.z)
+#endif
+ ) {
/* Pop. */
node_addr = traversal_stack[stack_ptr].addr;
--stack_ptr;
continue;
}
-#endif
ssef dist;
int child_mask = NODE_INTERSECT(kg,
@@ -262,7 +268,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Primitive intersection. */
while(prim_addr < prim_addr2) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type);
bool hit;
@@ -297,6 +303,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_HAIR)
case PRIMITIVE_CURVE:
case PRIMITIVE_MOTION_CURVE: {
+ const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr);
if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
hit = bvh_cardinal_curve_intersect(kg,
isect_array,
@@ -306,7 +313,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
object,
prim_addr,
ray->time,
- type,
+ curve_type,
NULL,
0, 0);
}
@@ -319,7 +326,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
object,
prim_addr,
ray->time,
- type,
+ curve_type,
NULL,
0, 0);
}
diff --git a/intern/cycles/kernel/bvh/qbvh_subsurface.h b/intern/cycles/kernel/bvh/qbvh_subsurface.h
index ccd36df034a..84dc4003133 100644
--- a/intern/cycles/kernel/bvh/qbvh_subsurface.h
+++ b/intern/cycles/kernel/bvh/qbvh_subsurface.h
@@ -61,7 +61,7 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
ss_isect->num_hits = 0;
const int object_flag = kernel_tex_fetch(__object_flag, subsurface_object);
- if(!(object_flag & SD_TRANSFORM_APPLIED)) {
+ if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
#if BVH_FEATURE(BVH_MOTION)
Transform ob_itfm;
bvh_instance_motion_push(kg,
diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h
index f2d8e558dcc..10ae7bee852 100644
--- a/intern/cycles/kernel/bvh/qbvh_traversal.h
+++ b/intern/cycles/kernel/bvh/qbvh_traversal.h
@@ -117,6 +117,10 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
if(UNLIKELY(node_dist > isect->t)
+#if BVH_FEATURE(BVH_MOTION)
+ || UNLIKELY(ray->time < inodes.y)
+ || UNLIKELY(ray->time > inodes.z)
+#endif
#ifdef __VISIBILITY_FLAG__
|| (__float_as_uint(inodes.x) & visibility) == 0)
#endif
@@ -131,7 +135,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
int child_mask;
ssef dist;
- BVH_DEBUG_NEXT_STEP();
+ BVH_DEBUG_NEXT_NODE();
#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
if(difl != 0.0f) {
@@ -326,7 +330,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
for(; prim_addr < prim_addr2; prim_addr++) {
- BVH_DEBUG_NEXT_STEP();
+ BVH_DEBUG_NEXT_INTERSECTION();
kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
if(triangle_intersect(kg,
&isect_precalc,
@@ -347,7 +351,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
for(; prim_addr < prim_addr2; prim_addr++) {
- BVH_DEBUG_NEXT_STEP();
+ BVH_DEBUG_NEXT_INTERSECTION();
kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
if(motion_triangle_intersect(kg,
isect,
@@ -371,8 +375,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
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);
+ BVH_DEBUG_NEXT_INTERSECTION();
+ const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr);
+ kernel_assert((curve_type & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL));
bool hit;
if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
hit = bvh_cardinal_curve_intersect(kg,
@@ -383,7 +388,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
object,
prim_addr,
ray->time,
- type,
+ curve_type,
lcg_state,
difl,
extmax);
@@ -397,7 +402,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
object,
prim_addr,
ray->time,
- type,
+ curve_type,
lcg_state,
difl,
extmax);
diff --git a/intern/cycles/kernel/bvh/qbvh_volume.h b/intern/cycles/kernel/bvh/qbvh_volume.h
index 424710b69f2..dc6627e2dbb 100644
--- a/intern/cycles/kernel/bvh/qbvh_volume.h
+++ b/intern/cycles/kernel/bvh/qbvh_volume.h
@@ -293,9 +293,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Instance push. */
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) {
-
# if BVH_FEATURE(BVH_MOTION)
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
# else
diff --git a/intern/cycles/kernel/bvh/qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h
index eb48af6fc68..ff1fa92af6e 100644
--- a/intern/cycles/kernel/bvh/qbvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h
@@ -344,9 +344,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Instance push. */
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) {
-
# if BVH_FEATURE(BVH_MOTION)
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
# else
diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h
index 24ced934c8b..6838e26c242 100644
--- a/intern/cycles/kernel/geom/geom.h
+++ b/intern/cycles/kernel/geom/geom.h
@@ -23,6 +23,8 @@
#include "geom_subd_triangle.h"
#include "geom_triangle_intersect.h"
#include "geom_motion_triangle.h"
+#include "geom_motion_triangle_intersect.h"
+#include "geom_motion_triangle_shader.h"
#include "geom_motion_curve.h"
#include "geom_curve.h"
#include "geom_volume.h"
diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h
index 636dbcc71e0..9de335403ce 100644
--- a/intern/cycles/kernel/geom/geom_curve.h
+++ b/intern/cycles/kernel/geom/geom_curve.h
@@ -911,7 +911,7 @@ ccl_device_forceinline bool bvh_curve_intersect(KernelGlobals *kg, Intersection
# undef len3_squared
# undef len3
# undef dot3
-# endif
+#endif
}
ccl_device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3)
diff --git a/intern/cycles/kernel/geom/geom_motion_curve.h b/intern/cycles/kernel/geom/geom_motion_curve.h
index 80b33fad68b..dc1388b6643 100644
--- a/intern/cycles/kernel/geom/geom_motion_curve.h
+++ b/intern/cycles/kernel/geom/geom_motion_curve.h
@@ -50,12 +50,12 @@ ccl_device_inline int find_attribute_curve_motion(KernelGlobals *kg, int object,
ccl_device_inline void motion_curve_keys_for_step(KernelGlobals *kg, int offset, int numkeys, int numsteps, int step, int k0, int k1, float4 keys[2])
{
if(step == numsteps) {
- /* center step: regular vertex location */
+ /* center step: regular key location */
keys[0] = kernel_tex_fetch(__curve_keys, k0);
keys[1] = kernel_tex_fetch(__curve_keys, k1);
}
else {
- /* center step not stored in this array */
+ /* center step is not stored in this array */
if(step > numsteps)
step--;
@@ -97,14 +97,14 @@ ccl_device_inline void motion_curve_keys(KernelGlobals *kg, int object, int prim
ccl_device_inline void motion_cardinal_curve_keys_for_step(KernelGlobals *kg, int offset, int numkeys, int numsteps, int step, int k0, int k1, int k2, int k3, float4 keys[4])
{
if(step == numsteps) {
- /* center step: regular vertex location */
+ /* center step: regular key location */
keys[0] = kernel_tex_fetch(__curve_keys, k0);
keys[1] = kernel_tex_fetch(__curve_keys, k1);
keys[2] = kernel_tex_fetch(__curve_keys, k2);
keys[3] = kernel_tex_fetch(__curve_keys, k3);
}
else {
- /* center step not store in this array */
+ /* center step is not stored in this array */
if(step > numsteps)
step--;
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h
index 538c332c63a..4e84aa97776 100644
--- a/intern/cycles/kernel/geom/geom_motion_triangle.h
+++ b/intern/cycles/kernel/geom/geom_motion_triangle.h
@@ -76,7 +76,7 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, uint4
normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
}
else {
- /* center step not stored in this array */
+ /* center step is not stored in this array */
if(step > numsteps)
step--;
@@ -117,312 +117,4 @@ ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, i
verts[2] = (1.0f - t)*verts[2] + t*next_verts[2];
}
-/* Refine triangle intersection to more precise hit point. For rays that travel
- * far the precision is often not so good, this reintersects the primitive from
- * a closer distance. */
-
-ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float3 verts[3])
-{
- float3 P = ray->P;
- float3 D = ray->D;
- float t = isect->t;
-
-#ifdef __INTERSECTION_REFINE__
- if(isect->object != OBJECT_NONE) {
- if(UNLIKELY(t == 0.0f)) {
- return P;
- }
-# ifdef __OBJECT_MOTION__
- Transform tfm = ccl_fetch(sd, ob_itfm);
-# else
- Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
-# endif
-
- P = transform_point(&tfm, P);
- D = transform_direction(&tfm, D*t);
- D = normalize_len(D, &t);
- }
-
- P = P + D*t;
-
- /* compute refined intersection distance */
- const float3 e1 = verts[0] - verts[2];
- const float3 e2 = verts[1] - verts[2];
- const float3 s1 = cross(D, e2);
-
- const float invdivisor = 1.0f/dot(s1, e1);
- const float3 d = P - verts[2];
- const float3 s2 = cross(d, e1);
- float rt = dot(e2, s2)*invdivisor;
-
- /* compute refined position */
- P = P + D*rt;
-
- if(isect->object != OBJECT_NONE) {
-# ifdef __OBJECT_MOTION__
- Transform tfm = ccl_fetch(sd, ob_tfm);
-# else
- Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
-# endif
-
- P = transform_point(&tfm, P);
- }
-
- return P;
-#else
- return P + D*t;
-#endif
-}
-
-/* Same as above, except that isect->t is assumed to be in object space for instancing */
-
-#ifdef __SUBSURFACE__
-# if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86))
-ccl_device_noinline
-# else
-ccl_device_inline
-# endif
-float3 motion_triangle_refine_subsurface(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float3 verts[3])
-{
- float3 P = ray->P;
- float3 D = ray->D;
- float t = isect->t;
-
-# ifdef __INTERSECTION_REFINE__
- if(isect->object != OBJECT_NONE) {
-# ifdef __OBJECT_MOTION__
- Transform tfm = ccl_fetch(sd, ob_itfm);
-# else
- Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
-# endif
-
- P = transform_point(&tfm, P);
- D = transform_direction(&tfm, D);
- D = normalize(D);
- }
-
- P = P + D*t;
-
- /* compute refined intersection distance */
- const float3 e1 = verts[0] - verts[2];
- const float3 e2 = verts[1] - verts[2];
- const float3 s1 = cross(D, e2);
-
- const float invdivisor = 1.0f/dot(s1, e1);
- const float3 d = P - verts[2];
- const float3 s2 = cross(d, e1);
- float rt = dot(e2, s2)*invdivisor;
-
- P = P + D*rt;
-
- if(isect->object != OBJECT_NONE) {
-# ifdef __OBJECT_MOTION__
- Transform tfm = ccl_fetch(sd, ob_tfm);
-# else
- Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
-# endif
-
- P = transform_point(&tfm, P);
- }
-
- return P;
-# else
- return P + D*t;
-# endif
-}
-#endif
-
-/* Setup of motion triangle specific parts of ShaderData, moved into this one
- * function to more easily share computation of interpolated positions and
- * normals */
-
-/* return 3 triangle vertex normals */
-ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, bool subsurface)
-{
- /* get shader */
- ccl_fetch(sd, shader) = kernel_tex_fetch(__tri_shader, ccl_fetch(sd, prim));
-
- /* get motion info */
- int numsteps, numverts;
- object_motion_info(kg, ccl_fetch(sd, object), &numsteps, &numverts, NULL);
-
- /* figure out which steps we need to fetch and their interpolation factor */
- int maxstep = numsteps*2;
- int step = min((int)(ccl_fetch(sd, time)*maxstep), maxstep-1);
- float t = ccl_fetch(sd, time)*maxstep - step;
-
- /* find attribute */
- AttributeElement elem;
- int offset = find_attribute_motion(kg, ccl_fetch(sd, object), ATTR_STD_MOTION_VERTEX_POSITION, &elem);
- kernel_assert(offset != ATTR_STD_NOT_FOUND);
-
- /* fetch vertex coordinates */
- float3 verts[3], next_verts[3];
- 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);
-
- /* interpolate between steps */
- verts[0] = (1.0f - t)*verts[0] + t*next_verts[0];
- verts[1] = (1.0f - t)*verts[1] + t*next_verts[1];
- verts[2] = (1.0f - t)*verts[2] + t*next_verts[2];
-
- /* compute refined position */
-#ifdef __SUBSURFACE__
- if(!subsurface)
-#endif
- ccl_fetch(sd, P) = motion_triangle_refine(kg, sd, isect, ray, verts);
-#ifdef __SUBSURFACE__
- else
- ccl_fetch(sd, P) = motion_triangle_refine_subsurface(kg, sd, isect, ray, verts);
-#endif
-
- /* compute face normal */
- float3 Ng;
- if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED)
- Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0]));
- else
- Ng = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
-
- ccl_fetch(sd, Ng) = Ng;
- ccl_fetch(sd, N) = Ng;
-
- /* compute derivatives of P w.r.t. uv */
-#ifdef __DPDU__
- ccl_fetch(sd, dPdu) = (verts[0] - verts[2]);
- ccl_fetch(sd, dPdv) = (verts[1] - verts[2]);
-#endif
-
- /* compute smooth normal */
- if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) {
- /* find attribute */
- AttributeElement elem;
- int offset = find_attribute_motion(kg, ccl_fetch(sd, object), ATTR_STD_MOTION_VERTEX_NORMAL, &elem);
- kernel_assert(offset != ATTR_STD_NOT_FOUND);
-
- /* fetch vertex coordinates */
- float3 normals[3], next_normals[3];
- motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals);
- motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_normals);
-
- /* interpolate between steps */
- normals[0] = (1.0f - t)*normals[0] + t*next_normals[0];
- normals[1] = (1.0f - t)*normals[1] + t*next_normals[1];
- normals[2] = (1.0f - t)*normals[2] + t*next_normals[2];
-
- /* interpolate between vertices */
- float u = ccl_fetch(sd, u);
- float v = ccl_fetch(sd, v);
- float w = 1.0f - u - v;
- ccl_fetch(sd, N) = (u*normals[0] + v*normals[1] + w*normals[2]);
- }
-}
-
-/* Ray intersection. We simply compute the vertex positions at the given ray
- * time and do a ray intersection with the resulting triangle */
-
-ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg, Intersection *isect,
- float3 P, float3 dir, float time, uint visibility, int object, int prim_addr)
-{
- /* primitive index for vertex location lookup */
- int prim = kernel_tex_fetch(__prim_index, prim_addr);
- int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
-
- /* get vertex locations for intersection */
- float3 verts[3];
- motion_triangle_vertices(kg, fobject, prim, time, verts);
-
- /* ray-triangle intersection, unoptimized */
- float t, u, v;
-
- if(ray_triangle_intersect_uv(P, dir, isect->t, verts[2], verts[0], verts[1], &u, &v, &t)) {
-#ifdef __VISIBILITY_FLAG__
- /* visibility flag test. we do it here under the assumption
- * that most triangles are culled by node flags */
- if(kernel_tex_fetch(__prim_visibility, prim_addr) & visibility)
-#endif
- {
- isect->t = t;
- isect->u = u;
- isect->v = v;
- isect->prim = prim_addr;
- isect->object = object;
- isect->type = PRIMITIVE_MOTION_TRIANGLE;
-
- return true;
- }
- }
-
- return false;
-}
-
-/* Special ray intersection routines for subsurface scattering. In that case we
- * only want to intersect with primitives in the same object, and if case of
- * multiple hits we pick a single random primitive as the intersection point. */
-
-#ifdef __SUBSURFACE__
-ccl_device_inline void motion_triangle_intersect_subsurface(
- KernelGlobals *kg,
- SubsurfaceIntersection *ss_isect,
- float3 P,
- float3 dir,
- float time,
- int object,
- int prim_addr,
- float tmax,
- uint *lcg_state,
- int max_hits)
-{
- /* primitive index for vertex location lookup */
- int prim = kernel_tex_fetch(__prim_index, prim_addr);
- int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
-
- /* get vertex locations for intersection */
- float3 verts[3];
- motion_triangle_vertices(kg, fobject, prim, time, verts);
-
- /* ray-triangle intersection, unoptimized */
- 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;
-
- if(ss_isect->num_hits <= max_hits) {
- hit = ss_isect->num_hits - 1;
- }
- else {
- /* reservoir sampling: if we are at the maximum number of
- * hits, randomly replace element or skip it */
- hit = lcg_step_uint(lcg_state) % ss_isect->num_hits;
-
- if(hit >= max_hits)
- return;
- }
-
- /* record intersection */
- Intersection *isect = &ss_isect->hits[hit];
- isect->t = t;
- isect->u = u;
- isect->v = v;
- isect->prim = prim_addr;
- isect->object = object;
- isect->type = PRIMITIVE_MOTION_TRIANGLE;
-
- /* Record geometric normal. */
- ss_isect->Ng[hit] = normalize(cross(verts[1] - verts[0],
- verts[2] - verts[0]));
- }
-}
-#endif
-
CCL_NAMESPACE_END
-
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h b/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h
new file mode 100644
index 00000000000..d57d74ea882
--- /dev/null
+++ b/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+/* Motion Triangle Primitive
+ *
+ * These are stored as regular triangles, plus extra positions and normals at
+ * times other than the frame center. Computing the triangle vertex positions
+ * or normals at a given ray time is a matter of interpolation of the two steps
+ * between which the ray time lies.
+ *
+ * The extra positions and normals are stored as ATTR_STD_MOTION_VERTEX_POSITION
+ * and ATTR_STD_MOTION_VERTEX_NORMAL mesh attributes.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Refine triangle intersection to more precise hit point. For rays that travel
+ * far the precision is often not so good, this reintersects the primitive from
+ * a closer distance.
+ */
+
+ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg,
+ ShaderData *sd,
+ const Intersection *isect,
+ const Ray *ray,
+ float3 verts[3])
+{
+ float3 P = ray->P;
+ float3 D = ray->D;
+ float t = isect->t;
+
+#ifdef __INTERSECTION_REFINE__
+ if(isect->object != OBJECT_NONE) {
+ if(UNLIKELY(t == 0.0f)) {
+ return P;
+ }
+# ifdef __OBJECT_MOTION__
+ Transform tfm = ccl_fetch(sd, ob_itfm);
+# else
+ Transform tfm = object_fetch_transform(kg,
+ isect->object,
+ OBJECT_INVERSE_TRANSFORM);
+# endif
+
+ P = transform_point(&tfm, P);
+ D = transform_direction(&tfm, D*t);
+ D = normalize_len(D, &t);
+ }
+
+ P = P + D*t;
+
+ /* Compute refined intersection distance. */
+ const float3 e1 = verts[0] - verts[2];
+ const float3 e2 = verts[1] - verts[2];
+ const float3 s1 = cross(D, e2);
+
+ const float invdivisor = 1.0f/dot(s1, e1);
+ const float3 d = P - verts[2];
+ const float3 s2 = cross(d, e1);
+ float rt = dot(e2, s2)*invdivisor;
+
+ /* Compute refined position. */
+ P = P + D*rt;
+
+ if(isect->object != OBJECT_NONE) {
+# ifdef __OBJECT_MOTION__
+ Transform tfm = ccl_fetch(sd, ob_tfm);
+# else
+ Transform tfm = object_fetch_transform(kg,
+ isect->object,
+ OBJECT_TRANSFORM);
+# endif
+
+ P = transform_point(&tfm, P);
+ }
+
+ return P;
+#else
+ return P + D*t;
+#endif
+}
+
+/* Same as above, except that isect->t is assumed to be in object space
+ * for instancing.
+ */
+
+#ifdef __SUBSURFACE__
+# if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86))
+ccl_device_noinline
+# else
+ccl_device_inline
+# endif
+float3 motion_triangle_refine_subsurface(KernelGlobals *kg,
+ ShaderData *sd,
+ const Intersection *isect,
+ const Ray *ray,
+ float3 verts[3])
+{
+ float3 P = ray->P;
+ float3 D = ray->D;
+ float t = isect->t;
+
+# ifdef __INTERSECTION_REFINE__
+ if(isect->object != OBJECT_NONE) {
+# ifdef __OBJECT_MOTION__
+ Transform tfm = ccl_fetch(sd, ob_itfm);
+# else
+ Transform tfm = object_fetch_transform(kg,
+ isect->object,
+ OBJECT_INVERSE_TRANSFORM);
+# endif
+
+ P = transform_point(&tfm, P);
+ D = transform_direction(&tfm, D);
+ D = normalize(D);
+ }
+
+ P = P + D*t;
+
+ /* compute refined intersection distance */
+ const float3 e1 = verts[0] - verts[2];
+ const float3 e2 = verts[1] - verts[2];
+ const float3 s1 = cross(D, e2);
+
+ const float invdivisor = 1.0f/dot(s1, e1);
+ const float3 d = P - verts[2];
+ const float3 s2 = cross(d, e1);
+ float rt = dot(e2, s2)*invdivisor;
+
+ P = P + D*rt;
+
+ if(isect->object != OBJECT_NONE) {
+# ifdef __OBJECT_MOTION__
+ Transform tfm = ccl_fetch(sd, ob_tfm);
+# else
+ Transform tfm = object_fetch_transform(kg,
+ isect->object,
+ OBJECT_TRANSFORM);
+# endif
+
+ P = transform_point(&tfm, P);
+ }
+
+ return P;
+# else /* __INTERSECTION_REFINE__ */
+ return P + D*t;
+# endif /* __INTERSECTION_REFINE__ */
+}
+#endif /* __SUBSURFACE__ */
+
+
+/* Ray intersection. We simply compute the vertex positions at the given ray
+ * time and do a ray intersection with the resulting triangle.
+ */
+
+ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg,
+ Intersection *isect,
+ float3 P,
+ float3 dir,
+ float time,
+ uint visibility,
+ int object,
+ int prim_addr)
+{
+ /* Primitive index for vertex location lookup. */
+ int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ int fobject = (object == OBJECT_NONE)
+ ? kernel_tex_fetch(__prim_object, prim_addr)
+ : object;
+ /* Get vertex locations for intersection. */
+ float3 verts[3];
+ motion_triangle_vertices(kg, fobject, prim, time, verts);
+ /* Ray-triangle intersection, unoptimized. */
+ float t, u, v;
+ if(ray_triangle_intersect_uv(P,
+ dir,
+ isect->t,
+ verts[2], verts[0], verts[1],
+ &u, &v, &t))
+ {
+#ifdef __VISIBILITY_FLAG__
+ /* Visibility flag test. we do it here under the assumption
+ * that most triangles are culled by node flags.
+ */
+ if(kernel_tex_fetch(__prim_visibility, prim_addr) & visibility)
+#endif
+ {
+ isect->t = t;
+ isect->u = u;
+ isect->v = v;
+ isect->prim = prim_addr;
+ isect->object = object;
+ isect->type = PRIMITIVE_MOTION_TRIANGLE;
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Special ray intersection routines for subsurface scattering. In that case we
+ * only want to intersect with primitives in the same object, and if case of
+ * multiple hits we pick a single random primitive as the intersection point.
+ */
+#ifdef __SUBSURFACE__
+ccl_device_inline void motion_triangle_intersect_subsurface(
+ KernelGlobals *kg,
+ SubsurfaceIntersection *ss_isect,
+ float3 P,
+ float3 dir,
+ float time,
+ int object,
+ int prim_addr,
+ float tmax,
+ uint *lcg_state,
+ int max_hits)
+{
+ /* Primitive index for vertex location lookup. */
+ int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ int fobject = (object == OBJECT_NONE)
+ ? kernel_tex_fetch(__prim_object, prim_addr)
+ : object;
+ /* Get vertex locations for intersection. */
+ float3 verts[3];
+ motion_triangle_vertices(kg, fobject, prim, time, verts);
+ /* Ray-triangle intersection, unoptimized. */
+ 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;
+ if(ss_isect->num_hits <= max_hits) {
+ hit = ss_isect->num_hits - 1;
+ }
+ else {
+ /* Reservoir sampling: if we are at the maximum number of
+ * hits, randomly replace element or skip it.
+ */
+ hit = lcg_step_uint(lcg_state) % ss_isect->num_hits;
+
+ if(hit >= max_hits)
+ return;
+ }
+ /* Record intersection. */
+ Intersection *isect = &ss_isect->hits[hit];
+ isect->t = t;
+ isect->u = u;
+ isect->v = v;
+ isect->prim = prim_addr;
+ isect->object = object;
+ isect->type = PRIMITIVE_MOTION_TRIANGLE;
+ /* Record geometric normal. */
+ ss_isect->Ng[hit] = normalize(cross(verts[1] - verts[0],
+ verts[2] - verts[0]));
+ }
+}
+#endif /* __SUBSURFACE__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h
new file mode 100644
index 00000000000..0e024a05db6
--- /dev/null
+++ b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+/* Motion Triangle Primitive
+ *
+ * These are stored as regular triangles, plus extra positions and normals at
+ * times other than the frame center. Computing the triangle vertex positions
+ * or normals at a given ray time is a matter of interpolation of the two steps
+ * between which the ray time lies.
+ *
+ * The extra positions and normals are stored as ATTR_STD_MOTION_VERTEX_POSITION
+ * and ATTR_STD_MOTION_VERTEX_NORMAL mesh attributes.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Setup of motion triangle specific parts of ShaderData, moved into this one
+ * function to more easily share computation of interpolated positions and
+ * normals */
+
+/* return 3 triangle vertex normals */
+ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg,
+ ShaderData *sd, const
+ Intersection *isect,
+ const Ray *ray,
+ bool subsurface)
+{
+ /* Get shader. */
+ ccl_fetch(sd, shader) = kernel_tex_fetch(__tri_shader, ccl_fetch(sd, prim));
+ /* Get motion info. */
+ /* TODO(sergey): This logic is really similar to motion_triangle_vertices(),
+ * can we de-duplicate something here?
+ */
+ int numsteps, numverts;
+ object_motion_info(kg, ccl_fetch(sd, object), &numsteps, &numverts, NULL);
+ /* Figure out which steps we need to fetch and their interpolation factor. */
+ int maxstep = numsteps*2;
+ int step = min((int)(ccl_fetch(sd, time)*maxstep), maxstep-1);
+ float t = ccl_fetch(sd, time)*maxstep - step;
+ /* Find attribute. */
+ AttributeElement elem;
+ int offset = find_attribute_motion(kg, ccl_fetch(sd, object),
+ ATTR_STD_MOTION_VERTEX_POSITION,
+ &elem);
+ kernel_assert(offset != ATTR_STD_NOT_FOUND);
+ /* Fetch vertex coordinates. */
+ float3 verts[3], next_verts[3];
+ 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);
+ /* Interpolate between steps. */
+ verts[0] = (1.0f - t)*verts[0] + t*next_verts[0];
+ verts[1] = (1.0f - t)*verts[1] + t*next_verts[1];
+ verts[2] = (1.0f - t)*verts[2] + t*next_verts[2];
+ /* Compute refined position. */
+#ifdef __SUBSURFACE__
+ if(subsurface) {
+ ccl_fetch(sd, P) = motion_triangle_refine_subsurface(kg,
+ sd,
+ isect,
+ ray,
+ verts);
+ }
+ else
+#endif /* __SUBSURFACE__*/
+ {
+ ccl_fetch(sd, P) = motion_triangle_refine(kg, sd, isect, ray, verts);
+ }
+ /* Compute face normal. */
+ float3 Ng;
+ if(ccl_fetch(sd, object_flag) & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+ Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0]));
+ }
+ else {
+ Ng = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
+ }
+ ccl_fetch(sd, Ng) = Ng;
+ ccl_fetch(sd, N) = Ng;
+ /* Compute derivatives of P w.r.t. uv. */
+#ifdef __DPDU__
+ ccl_fetch(sd, dPdu) = (verts[0] - verts[2]);
+ ccl_fetch(sd, dPdv) = (verts[1] - verts[2]);
+#endif
+ /* Compute smooth normal. */
+ if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) {
+ /* Find attribute. */
+ AttributeElement elem;
+ int offset = find_attribute_motion(kg,
+ ccl_fetch(sd, object),
+ ATTR_STD_MOTION_VERTEX_NORMAL,
+ &elem);
+ kernel_assert(offset != ATTR_STD_NOT_FOUND);
+ /* Fetch vertex coordinates. */
+ float3 normals[3], next_normals[3];
+ motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals);
+ motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_normals);
+ /* Interpolate between steps. */
+ normals[0] = (1.0f - t)*normals[0] + t*next_normals[0];
+ normals[1] = (1.0f - t)*normals[1] + t*next_normals[1];
+ normals[2] = (1.0f - t)*normals[2] + t*next_normals[2];
+ /* Interpolate between vertices. */
+ float u = ccl_fetch(sd, u);
+ float v = ccl_fetch(sd, v);
+ float w = 1.0f - u - v;
+ ccl_fetch(sd, N) = (u*normals[0] + v*normals[1] + w*normals[2]);
+ }
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h
index 9f0fe032ba4..f51b2d18657 100644
--- a/intern/cycles/kernel/geom/geom_object.h
+++ b/intern/cycles/kernel/geom/geom_object.h
@@ -113,7 +113,6 @@ ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals *kg, int
ccl_device_inline Transform object_fetch_transform_motion_test(KernelGlobals *kg, int object, float time, Transform *itfm)
{
int object_flag = kernel_tex_fetch(__object_flag, object);
-
if(object_flag & SD_OBJECT_MOTION) {
/* if we do motion blur */
Transform tfm = object_fetch_transform_motion(kg, object, time);
diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h
index 4384c2093e9..8a73bb2f78b 100644
--- a/intern/cycles/kernel/geom/geom_primitive.h
+++ b/intern/cycles/kernel/geom/geom_primitive.h
@@ -157,8 +157,9 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
if(is_curve_primitive) {
center = curve_motion_center_location(kg, sd);
- if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED))
+ if(!(ccl_fetch(sd, object_flag) & SD_OBJECT_TRANSFORM_APPLIED)) {
object_position_transform(kg, sd, &center);
+ }
}
else
#endif
@@ -181,7 +182,7 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
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) {
+ if(is_curve_primitive && (ccl_fetch(sd, object_flag) & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
object_position_transform(kg, sd, &motion_pre);
object_position_transform(kg, sd, &motion_post);
}
diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h
index 5e286e59562..b5635d819bb 100644
--- a/intern/cycles/kernel/geom/geom_triangle.h
+++ b/intern/cycles/kernel/geom/geom_triangle.h
@@ -32,10 +32,12 @@ ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd)
const float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
/* return normal */
- if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED)
+ if(ccl_fetch(sd, object_flag) & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
return normalize(cross(v2 - v0, v1 - v0));
- else
+ }
+ else {
return normalize(cross(v1 - v0, v2 - v0));
+ }
}
/* point and normal on triangle */
@@ -46,20 +48,18 @@ ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int
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 */
int object_flag = kernel_tex_fetch(__object_flag, object);
-
/* compute normal */
- if(object_flag & SD_NEGATIVE_SCALE_APPLIED)
+ if(object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
*Ng = normalize(cross(v2 - v0, v1 - v0));
- else
+ }
+ else {
*Ng = normalize(cross(v1 - v0, v2 - v0));
-
+ }
/* shader`*/
*shader = kernel_tex_fetch(__tri_shader, prim);
}
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index 2de7320e4bd..bcd759e53ed 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -320,7 +320,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
P, Ng, Ng,
shader, object, prim,
u, v, 1.0f, 0.5f,
- !(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED),
+ !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED),
LAMP_NONE);
sd.I = sd.N;
diff --git a/intern/cycles/kernel/kernel_debug.h b/intern/cycles/kernel/kernel_debug.h
index 24d6458567e..5647bbae5b5 100644
--- a/intern/cycles/kernel/kernel_debug.h
+++ b/intern/cycles/kernel/kernel_debug.h
@@ -18,8 +18,9 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline void debug_data_init(DebugData *debug_data)
{
- debug_data->num_bvh_traversal_steps = 0;
+ debug_data->num_bvh_traversed_nodes = 0;
debug_data->num_bvh_traversed_instances = 0;
+ debug_data->num_bvh_intersections = 0;
debug_data->num_ray_bounces = 0;
}
@@ -30,16 +31,21 @@ ccl_device_inline void kernel_write_debug_passes(KernelGlobals *kg,
int sample)
{
int flag = kernel_data.film.pass_flag;
- if(flag & PASS_BVH_TRAVERSAL_STEPS) {
- kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversal_steps,
+ if(flag & PASS_BVH_TRAVERSED_NODES) {
+ kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversed_nodes,
sample,
- debug_data->num_bvh_traversal_steps);
+ debug_data->num_bvh_traversed_nodes);
}
if(flag & PASS_BVH_TRAVERSED_INSTANCES) {
kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversed_instances,
sample,
debug_data->num_bvh_traversed_instances);
}
+ if(flag & PASS_BVH_INTERSECTIONS) {
+ kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_intersections,
+ sample,
+ debug_data->num_bvh_intersections);
+ }
if(flag & PASS_RAY_BOUNCES) {
kernel_write_pass_float(buffer + kernel_data.film.pass_ray_bounces,
sample,
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index ea0b6439717..9baa9d54957 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -767,7 +767,7 @@ ccl_device void object_transform_light_sample(KernelGlobals *kg, LightSample *ls
{
#ifdef __INSTANCING__
/* instance transform */
- if(!(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED)) {
+ if(!(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED)) {
# ifdef __OBJECT_MOTION__
Transform itfm;
Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm);
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index f2e9fa357a6..eada6916e58 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -109,6 +109,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
/* intersect scene */
Intersection isect;
uint visibility = path_state_ray_visibility(kg, state);
+ if(state->bounce > kernel_data.integrator.ao_bounces) {
+ visibility = PATH_RAY_SHADOW;
+ ray->t = kernel_data.background.ao_distance;
+ }
bool hit = scene_intersect(kg,
*ray,
visibility,
@@ -292,6 +296,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
break;
}
+ else if(state->bounce > kernel_data.integrator.ao_bounces) {
+ break;
+ }
/* setup shading */
shader_setup_from_ray(kg,
@@ -452,7 +459,7 @@ bool kernel_path_subsurface_scatter(
# ifdef __VOLUME__
ss_indirect->need_update_volume_stack =
kernel_data.integrator.use_volumes &&
- ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME;
+ ccl_fetch(sd, object_flag) & SD_OBJECT_INTERSECTS_VOLUME;
# endif /* __VOLUME__ */
/* compute lighting with the BSDF closure */
@@ -627,6 +634,11 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg,
lcg_state = lcg_state_init(rng, &state, 0x51633e2d);
}
+ if(state.bounce > kernel_data.integrator.ao_bounces) {
+ visibility = PATH_RAY_SHADOW;
+ ray.t = kernel_data.background.ao_distance;
+ }
+
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);
@@ -634,8 +646,9 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg,
#ifdef __KERNEL_DEBUG__
if(state.flag & PATH_RAY_CAMERA) {
- debug_data.num_bvh_traversal_steps += isect.num_traversal_steps;
+ debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes;
debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
+ debug_data.num_bvh_intersections += isect.num_intersections;
}
debug_data.num_ray_bounces++;
#endif /* __KERNEL_DEBUG__ */
@@ -771,6 +784,9 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg,
break;
}
+ else if(state.bounce > kernel_data.integrator.ao_bounces) {
+ break;
+ }
/* setup shading */
shader_setup_from_ray(kg, &sd, &isect, &ray);
@@ -781,21 +797,25 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg,
/* holdout */
#ifdef __HOLDOUT__
- if((sd.flag & (SD_HOLDOUT|SD_HOLDOUT_MASK)) && (state.flag & PATH_RAY_CAMERA)) {
+ if(((sd.flag & SD_HOLDOUT) ||
+ (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) &&
+ (state.flag & PATH_RAY_CAMERA))
+ {
if(kernel_data.background.transparent) {
float3 holdout_weight;
-
- if(sd.flag & SD_HOLDOUT_MASK)
+ if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) {
holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
- else
+ }
+ else {
holdout_weight = shader_holdout_eval(kg, &sd);
-
+ }
/* any throughput is ok, should all be identical here */
L_transparent += average(holdout_weight*throughput);
}
- if(sd.flag & SD_HOLDOUT_MASK)
+ if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) {
break;
+ }
}
#endif /* __HOLDOUT__ */
diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h
index fba83bb6c35..d8ef12546c5 100644
--- a/intern/cycles/kernel/kernel_path_branched.h
+++ b/intern/cycles/kernel/kernel_path_branched.h
@@ -167,8 +167,9 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
true);
#ifdef __VOLUME__
Ray volume_ray = *ray;
- bool need_update_volume_stack = kernel_data.integrator.use_volumes &&
- ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME;
+ bool need_update_volume_stack =
+ kernel_data.integrator.use_volumes &&
+ ccl_fetch(sd, object_flag) & SD_OBJECT_INTERSECTS_VOLUME;
#endif /* __VOLUME__ */
/* compute lighting with the BSDF closure */
@@ -287,8 +288,9 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int
#endif /* __HAIR__ */
#ifdef __KERNEL_DEBUG__
- debug_data.num_bvh_traversal_steps += isect.num_traversal_steps;
+ debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes;
debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
+ debug_data.num_bvh_intersections += isect.num_intersections;
debug_data.num_ray_bounces++;
#endif /* __KERNEL_DEBUG__ */
@@ -476,21 +478,21 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int
/* holdout */
#ifdef __HOLDOUT__
- if(sd.flag & (SD_HOLDOUT|SD_HOLDOUT_MASK)) {
+ if((sd.flag & SD_HOLDOUT) || (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) {
if(kernel_data.background.transparent) {
float3 holdout_weight;
-
- if(sd.flag & SD_HOLDOUT_MASK)
+ if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) {
holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
- else
+ }
+ else {
holdout_weight = shader_holdout_eval(kg, &sd);
-
+ }
/* any throughput is ok, should all be identical here */
L_transparent += average(holdout_weight*throughput);
}
-
- if(sd.flag & SD_HOLDOUT_MASK)
+ if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) {
break;
+ }
}
#endif /* __HOLDOUT__ */
diff --git a/intern/cycles/kernel/kernel_path_common.h b/intern/cycles/kernel/kernel_path_common.h
index 13597eab287..7b903556bf9 100644
--- a/intern/cycles/kernel/kernel_path_common.h
+++ b/intern/cycles/kernel/kernel_path_common.h
@@ -30,7 +30,7 @@ ccl_device_inline void kernel_path_trace_setup(KernelGlobals *kg,
int num_samples = kernel_data.integrator.aa_samples;
- if(sample == 0) {
+ if(sample == kernel_data.integrator.start_sample) {
*rng_state = hash_int_2d(x, y);
}
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index c1388801ed9..1dcb9f280b0 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -38,7 +38,7 @@ CCL_NAMESPACE_BEGIN
#ifdef __OBJECT_MOTION__
ccl_device void shader_setup_object_transforms(KernelGlobals *kg, ShaderData *sd, float time)
{
- if(ccl_fetch(sd, flag) & SD_OBJECT_MOTION) {
+ if(ccl_fetch(sd, object_flag) & SD_OBJECT_MOTION) {
ccl_fetch(sd, ob_tfm) = object_fetch_transform_motion(kg, ccl_fetch(sd, object), time);
ccl_fetch(sd, ob_itfm) = transform_quick_inverse(ccl_fetch(sd, ob_tfm));
}
@@ -59,7 +59,9 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
#endif
ccl_fetch(sd, type) = isect->type;
- ccl_fetch(sd, flag) = kernel_tex_fetch(__object_flag, ccl_fetch(sd, object));
+ ccl_fetch(sd, flag) = 0;
+ ccl_fetch(sd, object_flag) = kernel_tex_fetch(__object_flag,
+ ccl_fetch(sd, object));
/* matrices and time */
#ifdef __OBJECT_MOTION__
@@ -160,10 +162,11 @@ void shader_setup_from_subsurface(
const Intersection *isect,
const Ray *ray)
{
- bool backfacing = sd->flag & SD_BACKFACING;
+ const bool backfacing = sd->flag & SD_BACKFACING;
/* object, matrices, time, ray_length stay the same */
- sd->flag = kernel_tex_fetch(__object_flag, sd->object);
+ sd->flag = 0;
+ sd->object_flag = kernel_tex_fetch(__object_flag, sd->object);
sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
sd->type = isect->type;
@@ -271,8 +274,10 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
ccl_fetch(sd, ray_length) = t;
ccl_fetch(sd, flag) = kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*SHADER_SIZE);
+ ccl_fetch(sd, object_flag) = 0;
if(ccl_fetch(sd, object) != OBJECT_NONE) {
- ccl_fetch(sd, flag) |= kernel_tex_fetch(__object_flag, ccl_fetch(sd, object));
+ ccl_fetch(sd, object_flag) |= kernel_tex_fetch(__object_flag,
+ ccl_fetch(sd, object));
#ifdef __OBJECT_MOTION__
shader_setup_object_transforms(kg, sd, time);
@@ -298,7 +303,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
ccl_fetch(sd, N) = triangle_smooth_normal(kg, Ng, ccl_fetch(sd, prim), ccl_fetch(sd, u), ccl_fetch(sd, v));
#ifdef __INSTANCING__
- if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED)) {
+ if(!(ccl_fetch(sd, object_flag) & SD_OBJECT_TRANSFORM_APPLIED)) {
object_normal_transform_auto(kg, sd, &ccl_fetch(sd, N));
}
#endif
@@ -309,7 +314,7 @@ ccl_device_inline 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(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED)) {
+ if(!(ccl_fetch(sd, object_flag) & SD_OBJECT_TRANSFORM_APPLIED)) {
object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdu));
object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdv));
}
@@ -364,7 +369,7 @@ ccl_device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
P, Ng, I,
shader, object, prim,
u, v, 0.0f, 0.5f,
- !(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED),
+ !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED),
LAMP_NONE);
}
@@ -379,6 +384,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
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)*SHADER_SIZE);
+ ccl_fetch(sd, object_flag) = 0;
#ifdef __OBJECT_MOTION__
ccl_fetch(sd, time) = ray->time;
#endif
@@ -420,6 +426,7 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s
sd->I = -ray->D;
sd->shader = SHADER_NONE;
sd->flag = 0;
+ sd->object_flag = 0;
#ifdef __OBJECT_MOTION__
sd->time = ray->time;
#endif
@@ -1027,6 +1034,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg,
sd->num_closure = 0;
sd->num_closure_extra = 0;
sd->flag = 0;
+ sd->object_flag = 0;
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
/* setup shaderdata from stack. it's mostly setup already in
@@ -1034,11 +1042,12 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg,
sd->object = stack[i].object;
sd->shader = stack[i].shader;
- sd->flag &= ~(SD_SHADER_FLAGS|SD_OBJECT_FLAGS);
+ sd->flag &= ~SD_SHADER_FLAGS;
sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+ sd->object_flag &= ~SD_OBJECT_FLAGS;
if(sd->object != OBJECT_NONE) {
- sd->flag |= kernel_tex_fetch(__object_flag, sd->object);
+ sd->object_flag |= kernel_tex_fetch(__object_flag, sd->object);
#ifdef __OBJECT_MOTION__
/* todo: this is inefficient for motion blur, we should be
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index ebf8a714ee0..29a4d70074b 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -346,9 +346,10 @@ typedef enum PassType {
PASS_SUBSURFACE_COLOR = (1 << 24),
PASS_LIGHT = (1 << 25), /* no real pass, used to force use_light_pass */
#ifdef __KERNEL_DEBUG__
- PASS_BVH_TRAVERSAL_STEPS = (1 << 26),
+ PASS_BVH_TRAVERSED_NODES = (1 << 26),
PASS_BVH_TRAVERSED_INSTANCES = (1 << 27),
- PASS_RAY_BOUNCES = (1 << 28),
+ PASS_BVH_INTERSECTIONS = (1 << 28),
+ PASS_RAY_BOUNCES = (1 << 29),
#endif
} PassType;
@@ -565,8 +566,9 @@ typedef ccl_addr_space struct Intersection {
int type;
#ifdef __KERNEL_DEBUG__
- int num_traversal_steps;
+ int num_traversed_nodes;
int num_traversed_instances;
+ int num_intersections;
#endif
} Intersection;
@@ -714,56 +716,108 @@ typedef enum ShaderContext {
/* Shader Data
*
* Main shader state at a point on the surface or in a volume. All coordinates
- * are in world space. */
+ * are in world space.
+ */
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? */
+ /* Runtime flags. */
+
+ /* Set when ray hits backside of surface. */
+ SD_BACKFACING = (1 << 0),
+ /* Shader has emissive closure. */
+ SD_EMISSION = (1 << 1),
+ /* Shader has BSDF closure. */
+ SD_BSDF = (1 << 2),
+ /* Shader has non-singular BSDF closure. */
+ SD_BSDF_HAS_EVAL = (1 << 3),
+ /* Shader has BSSRDF closure. */
+ SD_BSSRDF = (1 << 4),
+ /* Shader has holdout closure. */
+ SD_HOLDOUT = (1 << 5),
+ /* Shader has volume absorption closure. */
+ SD_ABSORPTION = (1 << 6),
+ /* Shader has have volume phase (scatter) closure. */
+ SD_SCATTER = (1 << 7),
+ /* Shader has AO closure. */
+ SD_AO = (1 << 8),
+ /* Shader has transparent closure. */
+ SD_TRANSPARENT = (1 << 9),
+ /* BSDF requires LCG for evaluation. */
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_CLOSURE_FLAGS = (SD_EMISSION |
+ SD_BSDF |
+ SD_BSDF_HAS_EVAL |
+ SD_BSSRDF |
+ SD_HOLDOUT |
+ SD_ABSORPTION |
+ SD_SCATTER |
+ SD_AO |
SD_BSDF_NEEDS_LCG),
- /* shader flags */
- 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_HAS_DISPLACEMENT|SD_HAS_CONSTANT_EMISSION),
-
- /* object flags */
- 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|
+ /* Shader flags. */
+
+ /* direct light sample */
+ SD_USE_MIS = (1 << 16),
+ /* Has transparent shadow. */
+ SD_HAS_TRANSPARENT_SHADOW = (1 << 17),
+ /* Has volume shader. */
+ SD_HAS_VOLUME = (1 << 18),
+ /* Has only volume shader, no surface. */
+ SD_HAS_ONLY_VOLUME = (1 << 19),
+ /* Has heterogeneous volume. */
+ SD_HETEROGENEOUS_VOLUME = (1 << 20),
+ /* BSSRDF normal uses bump. */
+ SD_HAS_BSSRDF_BUMP = (1 << 21),
+ /* Use equiangular volume sampling */
+ SD_VOLUME_EQUIANGULAR = (1 << 22),
+ /* Use multiple importance volume sampling. */
+ SD_VOLUME_MIS = (1 << 23),
+ /* Use cubic interpolation for voxels. */
+ SD_VOLUME_CUBIC = (1 << 24),
+ /* Has data connected to the displacement input. */
+ SD_HAS_BUMP = (1 << 25),
+ /* Has true displacement. */
+ SD_HAS_DISPLACEMENT = (1 << 26),
+ /* Has constant emission (value stored in __shader_flag) */
+ SD_HAS_CONSTANT_EMISSION = (1 << 27),
+
+ 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_HAS_DISPLACEMENT |
+ SD_HAS_CONSTANT_EMISSION)
+};
+
+ /* Object flags. */
+enum ShaderDataObjectFlag {
+ /* Holdout for camera rays. */
+ SD_OBJECT_HOLDOUT_MASK = (1 << 0),
+ /* Has object motion blur. */
+ SD_OBJECT_MOTION = (1 << 1),
+ /* Vertices have transform applied. */
+ SD_OBJECT_TRANSFORM_APPLIED = (1 << 2),
+ /* Vertices have negative scale applied. */
+ SD_OBJECT_NEGATIVE_SCALE_APPLIED = (1 << 3),
+ /* Object has a volume shader. */
+ SD_OBJECT_HAS_VOLUME = (1 << 4),
+ /* Object intersects AABB of an object with volume shader. */
+ SD_OBJECT_INTERSECTS_VOLUME = (1 << 5),
+ /* Has position for motion vertices. */
+ SD_OBJECT_HAS_VERTEX_MOTION = (1 << 6),
+
+ SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK |
+ SD_OBJECT_MOTION |
+ SD_OBJECT_TRANSFORM_APPLIED |
+ SD_OBJECT_NEGATIVE_SCALE_APPLIED |
+ SD_OBJECT_HAS_VOLUME |
SD_OBJECT_INTERSECTS_VOLUME)
};
@@ -802,6 +856,8 @@ typedef ccl_addr_space struct ShaderData {
ccl_soa_member(int, shader);
/* booleans describing shader, see ShaderDataFlag */
ccl_soa_member(int, flag);
+ /* booleans describing object of the shader, see ShaderDataObjectFlag */
+ ccl_soa_member(int, object_flag);
/* primitive id if there is one, ~0 otherwise */
ccl_soa_member(int, prim);
@@ -1075,10 +1131,10 @@ typedef struct KernelFilm {
int pass_pad4;
#ifdef __KERNEL_DEBUG__
- int pass_bvh_traversal_steps;
+ int pass_bvh_traversed_nodes;
int pass_bvh_traversed_instances;
+ int pass_bvh_intersections;
int pass_ray_bounces;
- int pass_pad3;
#endif
} KernelFilm;
static_assert_align(KernelFilm, 16);
@@ -1123,6 +1179,8 @@ typedef struct KernelIntegrator {
int max_transmission_bounce;
int max_volume_bounce;
+ int ao_bounces;
+
/* transparent */
int transparent_min_bounce;
int transparent_max_bounce;
@@ -1170,7 +1228,8 @@ typedef struct KernelIntegrator {
float weighting_adjust;
int use_gradients;
- int pad;
+ int start_sample;
+ int pad1, pad2, pad3;
} KernelIntegrator;
static_assert_align(KernelIntegrator, 16);
@@ -1228,10 +1287,9 @@ static_assert_align(KernelData, 16);
* really important here.
*/
typedef ccl_addr_space struct DebugData {
- // Total number of BVH node traversal steps and primitives intersections
- // for the camera rays.
- int num_bvh_traversal_steps;
+ int num_bvh_traversed_nodes;
int num_bvh_traversed_instances;
+ int num_bvh_intersections;
int num_ray_bounces;
} DebugData;
#endif
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 26543862b80..58bbdc33920 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -102,6 +102,8 @@ ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
#endif
ustring OSLRenderServices::u_path_ray_length("path:ray_length");
ustring OSLRenderServices::u_path_ray_depth("path:ray_depth");
+ustring OSLRenderServices::u_path_diffuse_depth("path:diffuse_depth");
+ustring OSLRenderServices::u_path_glossy_depth("path:glossy_depth");
ustring OSLRenderServices::u_path_transparent_depth("path:transparent_depth");
ustring OSLRenderServices::u_path_transmission_depth("path:transmission_depth");
ustring OSLRenderServices::u_trace("trace");
@@ -710,7 +712,7 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD
else
motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P);
- if(!(sd->flag & SD_TRANSFORM_APPLIED)) {
+ if(!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
object_position_transform(kg, sd, &P[0]);
object_position_transform(kg, sd, &P[1]);
object_position_transform(kg, sd, &P[2]);
@@ -759,6 +761,24 @@ bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *
int f = state->bounce;
return set_attribute_int(f, type, derivatives, val);
}
+ else if(name == u_path_diffuse_depth) {
+ /* Diffuse Ray Depth */
+ PathState *state = sd->osl_path_state;
+ int f = state->diffuse_bounce;
+ return set_attribute_int(f, type, derivatives, val);
+ }
+ else if(name == u_path_glossy_depth) {
+ /* Glossy Ray Depth */
+ PathState *state = sd->osl_path_state;
+ int f = state->glossy_bounce;
+ return set_attribute_int(f, type, derivatives, val);
+ }
+ else if(name == u_path_transmission_depth) {
+ /* Transmission Ray Depth */
+ PathState *state = sd->osl_path_state;
+ int f = state->transmission_bounce;
+ return set_attribute_int(f, type, derivatives, val);
+ }
else if(name == u_path_transparent_depth) {
/* Transparent Ray Depth */
PathState *state = sd->osl_path_state;
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
index 0f2e02c62b0..ec34ca77115 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -165,6 +165,8 @@ public:
static ustring u_curve_tangent_normal;
static ustring u_path_ray_length;
static ustring u_path_ray_depth;
+ static ustring u_path_diffuse_depth;
+ static ustring u_path_glossy_depth;
static ustring u_path_transparent_depth;
static ustring u_path_transmission_depth;
static ustring u_trace;
diff --git a/intern/cycles/kernel/shaders/node_light_path.osl b/intern/cycles/kernel/shaders/node_light_path.osl
index a021a40467d..64fe4c20132 100644
--- a/intern/cycles/kernel/shaders/node_light_path.osl
+++ b/intern/cycles/kernel/shaders/node_light_path.osl
@@ -27,6 +27,8 @@ shader node_light_path(
output float IsVolumeScatterRay = 0.0,
output float RayLength = 0.0,
output float RayDepth = 0.0,
+ output float DiffuseDepth = 0.0,
+ output float GlossyDepth = 0.0,
output float TransparentDepth = 0.0,
output float TransmissionDepth = 0.0)
{
@@ -45,6 +47,14 @@ shader node_light_path(
getattribute("path:ray_depth", ray_depth);
RayDepth = (float)ray_depth;
+ int diffuse_depth;
+ getattribute("path:diffuse_depth", diffuse_depth);
+ DiffuseDepth = (float)diffuse_depth;
+
+ int glossy_depth;
+ getattribute("path:glossy_depth", glossy_depth);
+ GlossyDepth = (float)glossy_depth;
+
int transparent_depth;
getattribute("path:transparent_depth", transparent_depth);
TransparentDepth = (float)transparent_depth;
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 435d1171d5c..5d951b972ed 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
@@ -137,22 +137,22 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao(
/* holdout */
#ifdef __HOLDOUT__
- if((ccl_fetch(sd, flag) & (SD_HOLDOUT|SD_HOLDOUT_MASK)) &&
+ if(((ccl_fetch(sd, flag) & SD_HOLDOUT) ||
+ (ccl_fetch(sd, object_flag) & SD_OBJECT_HOLDOUT_MASK)) &&
(state->flag & PATH_RAY_CAMERA))
{
if(kernel_data.background.transparent) {
float3 holdout_weight;
-
- if(ccl_fetch(sd, flag) & SD_HOLDOUT_MASK)
+ if(ccl_fetch(sd, object_flag) & SD_OBJECT_HOLDOUT_MASK) {
holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
- else
+ }
+ else {
holdout_weight = shader_holdout_eval(kg, sd);
-
+ }
/* any throughput is ok, should all be identical here */
L_transparent_coop[ray_index] += average(holdout_weight*throughput);
}
-
- if(ccl_fetch(sd, flag) & SD_HOLDOUT_MASK) {
+ if(ccl_fetch(sd, object_flag) & SD_OBJECT_HOLDOUT_MASK) {
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
*enqueue_flag = 1;
}
diff --git a/intern/cycles/kernel/split/kernel_scene_intersect.h b/intern/cycles/kernel/split/kernel_scene_intersect.h
index fc4b4ee38e5..2388580051f 100644
--- a/intern/cycles/kernel/split/kernel_scene_intersect.h
+++ b/intern/cycles/kernel/split/kernel_scene_intersect.h
@@ -116,8 +116,9 @@ ccl_device void kernel_scene_intersect(
#ifdef __KERNEL_DEBUG__
if(state.flag & PATH_RAY_CAMERA) {
- debug_data->num_bvh_traversal_steps += isect->num_traversal_steps;
+ debug_data->num_bvh_traversed_nodes += isect->num_traversed_nodes;
debug_data->num_bvh_traversed_instances += isect->num_traversed_instances;
+ debug_data->num_bvh_intersections += isect->num_intersections;
}
debug_data->num_ray_bounces++;
#endif
diff --git a/intern/cycles/kernel/svm/svm_light_path.h b/intern/cycles/kernel/svm/svm_light_path.h
index f35ea05048b..04f6f623f18 100644
--- a/intern/cycles/kernel/svm/svm_light_path.h
+++ b/intern/cycles/kernel/svm/svm_light_path.h
@@ -34,6 +34,8 @@ ccl_device void svm_node_light_path(ShaderData *sd, ccl_addr_space PathState *st
case NODE_LP_backfacing: info = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f: 0.0f; break;
case NODE_LP_ray_length: info = ccl_fetch(sd, ray_length); break;
case NODE_LP_ray_depth: info = (float)state->bounce; break;
+ case NODE_LP_ray_diffuse: info = (float)state->diffuse_bounce; break;
+ case NODE_LP_ray_glossy: info = (float)state->glossy_bounce; break;
case NODE_LP_ray_transparent: info = (float)state->transparent_bounce; break;
case NODE_LP_ray_transmission: info = (float)state->transmission_bounce; break;
}
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index 77d3398b449..95920d5906c 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -188,6 +188,8 @@ typedef enum NodeLightPath {
NODE_LP_backfacing,
NODE_LP_ray_length,
NODE_LP_ray_depth,
+ NODE_LP_ray_diffuse,
+ NODE_LP_ray_glossy,
NODE_LP_ray_transparent,
NODE_LP_ray_transmission,
} NodeLightPath;
diff --git a/intern/cycles/kernel/svm/svm_wireframe.h b/intern/cycles/kernel/svm/svm_wireframe.h
index 6eed9bc1a99..87e40791333 100644
--- a/intern/cycles/kernel/svm/svm_wireframe.h
+++ b/intern/cycles/kernel/svm/svm_wireframe.h
@@ -57,7 +57,7 @@ ccl_device_inline float wireframe(KernelGlobals *kg,
else
motion_triangle_vertices(kg, ccl_fetch(sd, object), ccl_fetch(sd, prim), ccl_fetch(sd, time), Co);
- if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED)) {
+ if(!(ccl_fetch(sd, object_flag) & SD_OBJECT_TRANSFORM_APPLIED)) {
object_position_transform(kg, sd, &Co[0]);
object_position_transform(kg, sd, &Co[1]);
object_position_transform(kg, sd, &Co[2]);
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index 8f00ea625f0..34e3d1e901f 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -339,7 +339,10 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
}
}
#ifdef WITH_CYCLES_DEBUG
- else if(type == PASS_BVH_TRAVERSAL_STEPS || type == PASS_RAY_BOUNCES) {
+ else if(type == PASS_BVH_TRAVERSED_NODES ||
+ type == PASS_BVH_TRAVERSED_INSTANCES ||
+ type == PASS_BVH_INTERSECTIONS ||
+ type == PASS_RAY_BOUNCES) {
if(read_pixels) {
FOREACH_PIXEL
in[0] = pixels[0]*scale;
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index afca94e8524..ce53bce1894 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -154,14 +154,9 @@ void Pass::add(PassType type, array<Pass>& passes)
pass.components = 0;
break;
#ifdef WITH_CYCLES_DEBUG
- case PASS_BVH_TRAVERSAL_STEPS:
- pass.components = 1;
- pass.exposure = false;
- break;
+ case PASS_BVH_TRAVERSED_NODES:
case PASS_BVH_TRAVERSED_INSTANCES:
- pass.components = 1;
- pass.exposure = false;
- break;
+ case PASS_BVH_INTERSECTIONS:
case PASS_RAY_BOUNCES:
pass.components = 1;
pass.exposure = false;
@@ -425,12 +420,15 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
break;
#ifdef WITH_CYCLES_DEBUG
- case PASS_BVH_TRAVERSAL_STEPS:
- kfilm->pass_bvh_traversal_steps = kfilm->pass_stride;
+ case PASS_BVH_TRAVERSED_NODES:
+ kfilm->pass_bvh_traversed_nodes = kfilm->pass_stride;
break;
case PASS_BVH_TRAVERSED_INSTANCES:
kfilm->pass_bvh_traversed_instances = kfilm->pass_stride;
break;
+ case PASS_BVH_INTERSECTIONS:
+ kfilm->pass_bvh_intersections = kfilm->pass_stride;
+ break;
case PASS_RAY_BOUNCES:
kfilm->pass_ray_bounces = kfilm->pass_stride;
break;
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index ab830b19c57..fd8a1262208 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -258,12 +258,14 @@ static bool image_equals(ImageManager::Image *image,
const string& filename,
void *builtin_data,
InterpolationType interpolation,
- ExtensionType extension)
+ ExtensionType extension,
+ bool use_alpha)
{
return image->filename == filename &&
image->builtin_data == builtin_data &&
image->interpolation == interpolation &&
- image->extension == extension;
+ image->extension == extension &&
+ image->use_alpha == use_alpha;
}
int ImageManager::add_image(const string& filename,
@@ -305,7 +307,8 @@ int ImageManager::add_image(const string& filename,
filename,
builtin_data,
interpolation,
- extension))
+ extension,
+ use_alpha))
{
if(img->frame != frame) {
img->frame = frame;
@@ -377,7 +380,8 @@ void ImageManager::remove_image(int flat_slot)
void ImageManager::remove_image(const string& filename,
void *builtin_data,
InterpolationType interpolation,
- ExtensionType extension)
+ ExtensionType extension,
+ bool use_alpha)
{
size_t slot;
@@ -387,7 +391,8 @@ void ImageManager::remove_image(const string& filename,
filename,
builtin_data,
interpolation,
- extension))
+ extension,
+ use_alpha))
{
remove_image(type_index_to_flattened_slot(slot, (ImageDataType)type));
return;
@@ -403,7 +408,8 @@ void ImageManager::remove_image(const string& filename,
void ImageManager::tag_reload_image(const string& filename,
void *builtin_data,
InterpolationType interpolation,
- ExtensionType extension)
+ ExtensionType extension,
+ bool use_alpha)
{
for(size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
for(size_t slot = 0; slot < images[type].size(); slot++) {
@@ -411,7 +417,8 @@ void ImageManager::tag_reload_image(const string& filename,
filename,
builtin_data,
interpolation,
- extension))
+ extension,
+ use_alpha))
{
images[type][slot]->need_load = true;
break;
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 47bbd92347c..494c74f0cdd 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -61,11 +61,13 @@ public:
void remove_image(const string& filename,
void *builtin_data,
InterpolationType interpolation,
- ExtensionType extension);
+ ExtensionType extension,
+ bool use_alpha);
void tag_reload_image(const string& filename,
void *builtin_data,
InterpolationType interpolation,
- ExtensionType extension);
+ ExtensionType extension,
+ bool use_alpha);
ImageDataType get_image_metadata(const string& filename, void *builtin_data, bool& is_linear);
void device_update(Device *device,
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index b7eb3bf6169..3289d6f2c1f 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -43,6 +43,8 @@ NODE_DEFINE(Integrator)
SOCKET_INT(transparent_max_bounce, "Transparent Max Bounce", 7);
SOCKET_BOOLEAN(transparent_shadows, "Transparent Shadows", false);
+ SOCKET_INT(ao_bounces, "AO Bounces", 0);
+
SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024);
SOCKET_FLOAT(volume_step_size, "Volume Step Size", 0.1f);
@@ -62,6 +64,7 @@ NODE_DEFINE(Integrator)
SOCKET_INT(mesh_light_samples, "Mesh Light Samples", 1);
SOCKET_INT(subsurface_samples, "Subsurface Samples", 1);
SOCKET_INT(volume_samples, "Volume Samples", 1);
+ SOCKET_INT(start_sample, "Start Sample", 0);
SOCKET_BOOLEAN(sample_all_lights_direct, "Sample All Lights Direct", true);
SOCKET_BOOLEAN(sample_all_lights_indirect, "Sample All Lights Indirect", true);
@@ -116,6 +119,13 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->transparent_max_bounce = transparent_max_bounce + 1;
kintegrator->transparent_min_bounce = transparent_min_bounce + 1;
+ if(ao_bounces == 0) {
+ kintegrator->ao_bounces = INT_MAX;
+ }
+ else {
+ kintegrator->ao_bounces = ao_bounces - 1;
+ }
+
/* Transparent Shadows
* We only need to enable transparent shadows, if we actually have
* transparent shaders in the scene. Otherwise we can disable it
@@ -157,6 +167,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->mesh_light_samples = mesh_light_samples;
kintegrator->subsurface_samples = subsurface_samples;
kintegrator->volume_samples = volume_samples;
+ kintegrator->start_sample = start_sample;
if(method == BRANCHED_PATH) {
kintegrator->sample_all_lights_direct = sample_all_lights_direct;
diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h
index 8c22547ed24..f96886bcd27 100644
--- a/intern/cycles/render/integrator.h
+++ b/intern/cycles/render/integrator.h
@@ -43,6 +43,8 @@ public:
int transparent_max_bounce;
bool transparent_shadows;
+ int ao_bounces;
+
int volume_max_steps;
float volume_step_size;
@@ -64,6 +66,7 @@ public:
int mesh_light_samples;
int subsurface_samples;
int volume_samples;
+ int start_sample;
bool sample_all_lights_direct;
bool sample_all_lights_indirect;
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index bf7c893a3b0..c9766fb5f3e 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -49,6 +49,64 @@ void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox& bounds) const
bounds.grow(verts[v[2]]);
}
+void Mesh::Triangle::motion_verts(const float3 *verts,
+ const float3 *vert_steps,
+ size_t num_verts,
+ size_t num_steps,
+ float time,
+ float3 r_verts[3]) const
+{
+ /* Figure out which steps we need to fetch and their interpolation factor. */
+ const size_t max_step = num_steps - 1;
+ const size_t step = min((int)(time * max_step), max_step - 1);
+ const float t = time*max_step - step;
+ /* Fetch vertex coordinates. */
+ float3 curr_verts[3];
+ float3 next_verts[3];
+ verts_for_step(verts,
+ vert_steps,
+ num_verts,
+ num_steps,
+ step,
+ curr_verts);
+ verts_for_step(verts,
+ vert_steps,
+ num_verts,
+ num_steps,
+ step + 1,
+ next_verts);
+ /* Interpolate between steps. */
+ r_verts[0] = (1.0f - t)*curr_verts[0] + t*next_verts[0];
+ r_verts[1] = (1.0f - t)*curr_verts[1] + t*next_verts[1];
+ r_verts[2] = (1.0f - t)*curr_verts[2] + t*next_verts[2];
+}
+
+void Mesh::Triangle::verts_for_step(const float3 *verts,
+ const float3 *vert_steps,
+ size_t num_verts,
+ size_t num_steps,
+ size_t step,
+ float3 r_verts[3]) const
+{
+ const size_t center_step = ((num_steps - 1) / 2);
+ if(step == center_step) {
+ /* Center step: regular vertex location. */
+ r_verts[0] = verts[v[0]];
+ r_verts[1] = verts[v[1]];
+ r_verts[2] = verts[v[2]];
+ }
+ else {
+ /* Center step not stored in the attribute array array. */
+ if(step > center_step) {
+ step--;
+ }
+ size_t offset = step * num_verts;
+ r_verts[0] = vert_steps[offset + v[0]];
+ r_verts[1] = vert_steps[offset + v[1]];
+ r_verts[2] = vert_steps[offset + v[2]];
+ }
+}
+
/* Curve */
void Mesh::Curve::bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const
@@ -104,6 +162,205 @@ void Mesh::Curve::bounds_grow(const int k,
bounds.grow(upper, mr);
}
+void Mesh::Curve::bounds_grow(float4 keys[4], BoundBox& bounds) const
+{
+ float3 P[4] = {
+ float4_to_float3(keys[0]),
+ float4_to_float3(keys[1]),
+ float4_to_float3(keys[2]),
+ float4_to_float3(keys[3]),
+ };
+
+ 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(keys[1].w, keys[2].w);
+
+ bounds.grow(lower, mr);
+ bounds.grow(upper, mr);
+}
+
+void Mesh::Curve::motion_keys(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ float time,
+ size_t k0, size_t k1,
+ float4 r_keys[2]) const
+{
+ /* Figure out which steps we need to fetch and their interpolation factor. */
+ const size_t max_step = num_steps - 1;
+ const size_t step = min((int)(time * max_step), max_step - 1);
+ const float t = time*max_step - step;
+ /* Fetch vertex coordinates. */
+ float4 curr_keys[2];
+ float4 next_keys[2];
+ keys_for_step(curve_keys,
+ curve_radius,
+ key_steps,
+ num_curve_keys,
+ num_steps,
+ step,
+ k0, k1,
+ curr_keys);
+ keys_for_step(curve_keys,
+ curve_radius,
+ key_steps,
+ num_curve_keys,
+ num_steps,
+ step + 1,
+ k0, k1,
+ next_keys);
+ /* Interpolate between steps. */
+ r_keys[0] = (1.0f - t)*curr_keys[0] + t*next_keys[0];
+ r_keys[1] = (1.0f - t)*curr_keys[1] + t*next_keys[1];
+}
+
+void Mesh::Curve::cardinal_motion_keys(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ float time,
+ size_t k0, size_t k1,
+ size_t k2, size_t k3,
+ float4 r_keys[4]) const
+{
+ /* Figure out which steps we need to fetch and their interpolation factor. */
+ const size_t max_step = num_steps - 1;
+ const size_t step = min((int)(time * max_step), max_step - 1);
+ const float t = time*max_step - step;
+ /* Fetch vertex coordinates. */
+ float4 curr_keys[4];
+ float4 next_keys[4];
+ cardinal_keys_for_step(curve_keys,
+ curve_radius,
+ key_steps,
+ num_curve_keys,
+ num_steps,
+ step,
+ k0, k1, k2, k3,
+ curr_keys);
+ cardinal_keys_for_step(curve_keys,
+ curve_radius,
+ key_steps,
+ num_curve_keys,
+ num_steps,
+ step + 1,
+ k0, k1, k2, k3,
+ next_keys);
+ /* Interpolate between steps. */
+ r_keys[0] = (1.0f - t)*curr_keys[0] + t*next_keys[0];
+ r_keys[1] = (1.0f - t)*curr_keys[1] + t*next_keys[1];
+ r_keys[2] = (1.0f - t)*curr_keys[2] + t*next_keys[2];
+ r_keys[3] = (1.0f - t)*curr_keys[3] + t*next_keys[3];
+}
+
+void Mesh::Curve::keys_for_step(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ size_t step,
+ size_t k0, size_t k1,
+ float4 r_keys[2]) const
+{
+ k0 = max(k0, 0);
+ k1 = min(k1, num_keys - 1);
+ const size_t center_step = ((num_steps - 1) / 2);
+ if(step == center_step) {
+ /* Center step: regular key location. */
+ /* TODO(sergey): Consider adding make_float4(float3, float)
+ * function.
+ */
+ r_keys[0] = make_float4(curve_keys[first_key + k0].x,
+ curve_keys[first_key + k0].y,
+ curve_keys[first_key + k0].z,
+ curve_radius[first_key + k0]);
+ r_keys[1] = make_float4(curve_keys[first_key + k1].x,
+ curve_keys[first_key + k1].y,
+ curve_keys[first_key + k1].z,
+ curve_radius[first_key + k1]);
+ }
+ else {
+ /* Center step is not stored in this array. */
+ if(step > center_step) {
+ step--;
+ }
+ const size_t offset = first_key + step * num_curve_keys;
+ r_keys[0] = make_float4(key_steps[offset + k0].x,
+ key_steps[offset + k0].y,
+ key_steps[offset + k0].z,
+ curve_radius[first_key + k0]);
+ r_keys[1] = make_float4(key_steps[offset + k1].x,
+ key_steps[offset + k1].y,
+ key_steps[offset + k1].z,
+ curve_radius[first_key + k1]);
+ }
+}
+
+void Mesh::Curve::cardinal_keys_for_step(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ size_t step,
+ size_t k0, size_t k1,
+ size_t k2, size_t k3,
+ float4 r_keys[4]) const
+{
+ k0 = max(k0, 0);
+ k3 = min(k3, num_keys - 1);
+ const size_t center_step = ((num_steps - 1) / 2);
+ if(step == center_step) {
+ /* Center step: regular key location. */
+ r_keys[0] = make_float4(curve_keys[first_key + k0].x,
+ curve_keys[first_key + k0].y,
+ curve_keys[first_key + k0].z,
+ curve_radius[first_key + k0]);
+ r_keys[1] = make_float4(curve_keys[first_key + k1].x,
+ curve_keys[first_key + k1].y,
+ curve_keys[first_key + k1].z,
+ curve_radius[first_key + k1]);
+ r_keys[2] = make_float4(curve_keys[first_key + k2].x,
+ curve_keys[first_key + k2].y,
+ curve_keys[first_key + k2].z,
+ curve_radius[first_key + k2]);
+ r_keys[3] = make_float4(curve_keys[first_key + k3].x,
+ curve_keys[first_key + k3].y,
+ curve_keys[first_key + k3].z,
+ curve_radius[first_key + k3]);
+ }
+ else {
+ /* Center step is not stored in this array. */
+ if(step > center_step) {
+ step--;
+ }
+ const size_t offset = first_key + step * num_curve_keys;
+ r_keys[0] = make_float4(key_steps[offset + k0].x,
+ key_steps[offset + k0].y,
+ key_steps[offset + k0].z,
+ curve_radius[first_key + k0]);
+ r_keys[1] = make_float4(key_steps[offset + k1].x,
+ key_steps[offset + k1].y,
+ key_steps[offset + k1].z,
+ curve_radius[first_key + k1]);
+ r_keys[2] = make_float4(key_steps[offset + k2].x,
+ key_steps[offset + k2].y,
+ key_steps[offset + k2].z,
+ curve_radius[first_key + k2]);
+ r_keys[3] = make_float4(key_steps[offset + k3].x,
+ key_steps[offset + k3].y,
+ key_steps[offset + k3].z,
+ curve_radius[first_key + k3]);
+ }
+}
+
/* SubdFace */
float3 Mesh::SubdFace::normal(const Mesh *mesh) const
@@ -394,7 +651,7 @@ void Mesh::compute_bounds()
if(use_motion_blur && attr) {
size_t steps_size = verts.size() * (motion_steps - 1);
float3 *vert_steps = attr->data_float3();
-
+
for(size_t i = 0; i < steps_size; i++)
bnds.grow(vert_steps[i]);
}
@@ -403,7 +660,7 @@ void Mesh::compute_bounds()
if(use_motion_blur && curve_attr) {
size_t steps_size = curve_keys.size() * (motion_steps - 1);
float3 *key_steps = curve_attr->data_float3();
-
+
for(size_t i = 0; i < steps_size; i++)
bnds.grow(key_steps[i]);
}
@@ -417,11 +674,11 @@ void Mesh::compute_bounds()
for(size_t i = 0; i < curve_keys_size; i++)
bnds.grow_safe(curve_keys[i], curve_radius[i]);
-
+
if(use_motion_blur && attr) {
size_t steps_size = verts.size() * (motion_steps - 1);
float3 *vert_steps = attr->data_float3();
-
+
for(size_t i = 0; i < steps_size; i++)
bnds.grow_safe(vert_steps[i]);
}
@@ -429,7 +686,7 @@ void Mesh::compute_bounds()
if(use_motion_blur && curve_attr) {
size_t steps_size = curve_keys.size() * (motion_steps - 1);
float3 *key_steps = curve_attr->data_float3();
-
+
for(size_t i = 0; i < steps_size; i++)
bnds.grow_safe(key_steps[i]);
}
@@ -464,7 +721,7 @@ void Mesh::add_face_normals()
/* don't compute if already there */
if(attributes.find(ATTR_STD_FACE_NORMAL))
return;
-
+
/* get attributes */
Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL);
float3 *fN = attr_fN->data_float3();
@@ -796,6 +1053,8 @@ void Mesh::compute_bvh(DeviceScene *dscene,
bparams.use_qbvh = params->use_qbvh;
bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
params->use_bvh_unaligned_nodes;
+ bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
+ bparams.num_motion_curve_steps = params->num_bvh_time_steps;
delete bvh;
bvh = BVH::create(bparams, objects);
@@ -1002,7 +1261,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
if(attr_map_stride == 0)
return;
-
+
/* create attribute map */
uint4 *attr_map = dscene->attributes_map.resize(attr_map_stride*scene->objects.size());
memset(attr_map, 0, dscene->attributes_map.size()*sizeof(uint));
@@ -1564,6 +1823,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
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;
+ bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps;
+ bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps;
delete bvh;
bvh = BVH::create(bparams, scene->objects);
@@ -1946,14 +2207,14 @@ bool Mesh::need_attribute(Scene *scene, AttributeStandard std)
{
if(std == ATTR_STD_NONE)
return false;
-
+
if(scene->need_global_attribute(std))
return true;
foreach(Shader *shader, used_shaders)
if(shader->attributes.find(std))
return true;
-
+
return false;
}
@@ -1965,9 +2226,8 @@ bool Mesh::need_attribute(Scene * /*scene*/, ustring name)
foreach(Shader *shader, used_shaders)
if(shader->attributes.find(name))
return true;
-
+
return false;
}
CCL_NAMESPACE_END
-
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index c0310f45840..5f33e30eac2 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -31,6 +31,7 @@
CCL_NAMESPACE_BEGIN
+class Attribute;
class BVH;
class Device;
class DeviceScene;
@@ -54,11 +55,27 @@ public:
int v[3];
void bounds_grow(const float3 *verts, BoundBox& bounds) const;
+
+ void motion_verts(const float3 *verts,
+ const float3 *vert_steps,
+ size_t num_verts,
+ size_t num_steps,
+ float time,
+ float3 r_verts[3]) const;
+
+ void verts_for_step(const float3 *verts,
+ const float3 *vert_steps,
+ size_t num_verts,
+ size_t num_steps,
+ size_t step,
+ float3 r_verts[3]) const;
};
Triangle get_triangle(size_t i) const
{
- Triangle tri = {{triangles[i*3 + 0], triangles[i*3 + 1], triangles[i*3 + 2]}};
+ Triangle tri = {{triangles[i*3 + 0],
+ triangles[i*3 + 1],
+ triangles[i*3 + 2]}};
return tri;
}
@@ -78,11 +95,48 @@ public:
const float3 *curve_keys,
const float *curve_radius,
BoundBox& bounds) const;
+ void bounds_grow(float4 keys[4], BoundBox& bounds) const;
void bounds_grow(const int k,
const float3 *curve_keys,
const float *curve_radius,
const Transform& aligned_space,
BoundBox& bounds) const;
+
+ void motion_keys(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ float time,
+ size_t k0, size_t k1,
+ float4 r_keys[2]) const;
+ void cardinal_motion_keys(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ float time,
+ size_t k0, size_t k1,
+ size_t k2, size_t k3,
+ float4 r_keys[4]) const;
+
+ void keys_for_step(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ size_t step,
+ size_t k0, size_t k1,
+ float4 r_keys[2]) const;
+ void cardinal_keys_for_step(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ size_t step,
+ size_t k0, size_t k1,
+ size_t k2, size_t k3,
+ float4 r_keys[4]) const;
};
Curve get_curve(size_t i) const
diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp
index 913c3c74b42..57c76a9f1c8 100644
--- a/intern/cycles/render/mesh_subdivision.cpp
+++ b/intern/cycles/render/mesh_subdivision.cpp
@@ -92,7 +92,7 @@ namespace Far {
if(vert_edges.size() == 2) {
float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]);
- sharpness = min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1]));
+ sharpness = ccl::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1]));
setBaseVertexSharpness(refiner, i, sharpness);
}
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index c7f37a13fba..13b149eddfa 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -263,7 +263,8 @@ ImageTextureNode::~ImageTextureNode()
image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
- extension);
+ extension,
+ use_alpha);
}
}
@@ -462,7 +463,8 @@ EnvironmentTextureNode::~EnvironmentTextureNode()
image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
- EXTENSION_REPEAT);
+ EXTENSION_REPEAT,
+ use_alpha);
}
}
@@ -1381,7 +1383,8 @@ PointDensityTextureNode::~PointDensityTextureNode()
image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
- EXTENSION_CLIP);
+ EXTENSION_CLIP,
+ true);
}
}
@@ -3027,6 +3030,8 @@ NODE_DEFINE(LightPathNode)
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(diffuse_depth, "Diffuse Depth");
+ SOCKET_OUT_FLOAT(glossy_depth, "Glossy Depth");
SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth");
SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth");
@@ -3093,6 +3098,16 @@ void LightPathNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, compiler.stack_assign(out));
}
+ out = output("Diffuse Depth");
+ if(!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_diffuse, compiler.stack_assign(out));
+ }
+
+ out = output("Glossy Depth");
+ if(!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_glossy, compiler.stack_assign(out));
+ }
+
out = output("Transparent Depth");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, compiler.stack_assign(out));
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index 8b8b988b969..8342f376836 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -166,7 +166,7 @@ void Object::apply_transform(bool apply_to_motion)
float3 c0 = transform_get_column(&tfm, 0);
float3 c1 = transform_get_column(&tfm, 1);
float3 c2 = transform_get_column(&tfm, 2);
- float scalar = pow(fabsf(dot(cross(c0, c1), c2)), 1.0f/3.0f);
+ float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f/3.0f);
/* apply transform to curve keys */
for(size_t i = 0; i < mesh->curve_keys.size(); i++) {
@@ -410,7 +410,7 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
/* Object flag. */
if(ob->use_holdout) {
- flag |= SD_HOLDOUT_MASK;
+ flag |= SD_OBJECT_HOLDOUT_MASK;
}
state->object_flag[object_index] = flag;
@@ -716,9 +716,9 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
if(progress.get_cancel()) return;
}
- object_flag[i] |= SD_TRANSFORM_APPLIED;
+ object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED;
if(object->mesh->transform_negative_scaled)
- object_flag[i] |= SD_NEGATIVE_SCALE_APPLIED;
+ object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED;
}
else
have_instancing = true;
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index df9363cc768..8768682043f 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -143,6 +143,7 @@ public:
} bvh_type;
bool use_bvh_spatial_split;
bool use_bvh_unaligned_nodes;
+ int num_bvh_time_steps;
bool use_qbvh;
bool persistent_data;
int texture_limit;
@@ -153,6 +154,7 @@ public:
bvh_type = BVH_DYNAMIC;
use_bvh_spatial_split = false;
use_bvh_unaligned_nodes = true;
+ num_bvh_time_steps = 0;
use_qbvh = false;
persistent_data = false;
texture_limit = 0;
@@ -163,6 +165,7 @@ public:
&& bvh_type == params.bvh_type
&& use_bvh_spatial_split == params.use_bvh_spatial_split
&& use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes
+ && num_bvh_time_steps == params.num_bvh_time_steps
&& use_qbvh == params.use_qbvh
&& persistent_data == params.persistent_data
&& texture_limit == params.texture_limit); }
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 45cc860c435..dccb0e66100 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -496,6 +496,8 @@ void Session::release_tile(RenderTile& rtile)
{
thread_scoped_lock tile_lock(tile_mutex);
+ progress.add_finished_tile();
+
bool delete_tile;
if(tile_manager.return_tile(rtile.tile_index, delete_tile)) {
@@ -994,11 +996,11 @@ void Session::update_status_time(bool show_pause, bool show_done)
substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles);
- if(device->show_samples() || (is_cpu && is_last_tile))
- {
+ if(device->show_samples() || (is_cpu && is_last_tile)) {
/* Some devices automatically support showing the sample number:
* - CUDADevice
- * - OpenCLDevice when using the megakernel (the split kernel renders multiple samples at the same time, so the current sample isn't really defined)
+ * - OpenCLDevice when using the megakernel (the split kernel renders multiple
+ * samples at the same time, so the current sample isn't really defined)
* - CPUDevice when using one thread
* For these devices, the current sample is always shown.
*
diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp
index 83c31a9a609..8218c9b433f 100644
--- a/intern/cycles/render/tile.cpp
+++ b/intern/cycles/render/tile.cpp
@@ -177,7 +177,7 @@ void TileManager::set_samples(int num_samples_)
divider >>= 1;
}
- state.total_pixel_samples = pixel_samples + get_num_effective_samples() * params.width*params.height;
+ state.total_pixel_samples = pixel_samples + (uint64_t)get_num_effective_samples() * params.width*params.height;
if(schedule_denoising) {
state.total_pixel_samples += params.width*params.height;
}
diff --git a/intern/cycles/test/CMakeLists.txt b/intern/cycles/test/CMakeLists.txt
index c60a99903e4..85358e3b64b 100644
--- a/intern/cycles/test/CMakeLists.txt
+++ b/intern/cycles/test/CMakeLists.txt
@@ -54,12 +54,23 @@ if(WITH_CYCLES_OPENSUBDIV)
endif()
list(APPEND ALL_CYCLES_LIBRARIES
${BOOST_LIBRARIES}
+ ${PNG_LIBRARIES}
+ ${JPEG_LIBRARIES}
+ ${ZLIB_LIBRARIES}
+ ${TIFF_LIBRARY}
+ ${OPENIMAGEIO_LIBRARIES}
+ ${OPENEXR_LIBRARIES}
)
include_directories(${INC})
-link_directories(${BOOST_LIBPATH})
-link_directories(${OPENIMAGEIO_LIBPATH})
+link_directories(${OPENIMAGEIO_LIBPATH}
+ ${BOOST_LIBPATH}
+ ${PNG_LIBPATH}
+ ${JPEG_LIBPATH}
+ ${ZLIB_LIBPATH}
+ ${TIFF_LIBPATH}
+ ${OPENEXR_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}")
diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h
index 599222da9c5..dfe4977aef3 100644
--- a/intern/cycles/util/util_boundbox.h
+++ b/intern/cycles/util/util_boundbox.h
@@ -25,8 +25,6 @@
#include "util_transform.h"
#include "util_types.h"
-using namespace std;
-
CCL_NAMESPACE_BEGIN
/* 3D BoundBox */
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index db4946fe5b0..64cf8b24168 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -22,6 +22,11 @@
* Basic math functions on scalar and vector types. This header is used by
* both the kernel code when compiled as C++, and other C++ non-kernel code. */
+#ifndef __KERNEL_GPU__
+# include <cmath>
+#endif
+
+
#ifndef __KERNEL_OPENCL__
#include <float.h>
@@ -97,6 +102,9 @@ ccl_device_inline float fminf(float a, float b)
#ifndef __KERNEL_GPU__
+using std::isfinite;
+using std::isnan;
+
ccl_device_inline int abs(int x)
{
return (x > 0)? x: -x;
@@ -1262,6 +1270,20 @@ ccl_device_inline float __uint_as_float(uint i)
return u.f;
}
+/* Versions of functions which are safe for fast math. */
+ccl_device_inline bool isnan_safe(float f)
+{
+ unsigned int x = __float_as_uint(f);
+ return (x << 1) > 0xff000000u;
+}
+
+ccl_device_inline bool isfinite_safe(float f)
+{
+ /* By IEEE 754 rule, 2*Inf equals Inf */
+ unsigned int x = __float_as_uint(f);
+ return (f == f) && (x == 0 || (f != 2.0f*f));
+}
+
/* Interpolation */
template<class A, class B> A lerp(const A& a, const A& b, const B& t)
diff --git a/intern/cycles/util/util_version.h b/intern/cycles/util/util_version.h
index 186a177d9d3..d609c739ac7 100644
--- a/intern/cycles/util/util_version.h
+++ b/intern/cycles/util/util_version.h
@@ -21,9 +21,9 @@
CCL_NAMESPACE_BEGIN
-#define CYCLES_VERSION_MAJOR 1
-#define CYCLES_VERSION_MINOR 7
-#define CYCLES_VERSION_PATCH 0
+#define CYCLES_VERSION_MAJOR 1
+#define CYCLES_VERSION_MINOR 8
+#define CYCLES_VERSION_PATCH 1
#define CYCLES_MAKE_VERSION_STRING2(a,b,c) #a "." #b "." #c
#define CYCLES_MAKE_VERSION_STRING(a,b,c) CYCLES_MAKE_VERSION_STRING2(a,b,c)
diff --git a/make.bat b/make.bat
index f3ec646dc8f..337a5517656 100644
--- a/make.bat
+++ b/make.bat
@@ -22,7 +22,7 @@ set MUST_CLEAN=
set NOBUILD=
set TARGET=
set WINDOWS_ARCH=
-
+set TESTS_CMAKE_ARGS=
:argv_loop
if NOT "%1" == "" (
@@ -35,6 +35,8 @@ if NOT "%1" == "" (
if "%1" == "debug" (
set BUILD_TYPE=Debug
REM Build Configurations
+ ) else if "%1" == "with_tests" (
+ set TESTS_CMAKE_ARGS=-DWITH_GTESTS=On
) else if "%1" == "full" (
set TARGET=Full
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
@@ -129,9 +131,6 @@ if "%BUILD_ARCH%"=="x64" (
)
-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%"=="" (
@@ -173,7 +172,7 @@ 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.
+ echo Visual Studio 2013 not found, trying Visual Studio 2015.
set BUILD_VS_VER=14
set BUILD_VS_YEAR=2015
goto DetectMSVC
@@ -184,6 +183,11 @@ if %ERRORLEVEL% NEQ 0 (
goto EOF
)
)
+
+
+set BUILD_DIR=%BUILD_DIR%_%TARGET%_%BUILD_ARCH%_vc%BUILD_VS_VER%_%BUILD_TYPE%
+
+
where /Q cmake
if %ERRORLEVEL% NEQ 0 (
echo Error: "CMake" command not in the PATH.
@@ -202,7 +206,7 @@ if "%TARGET%"=="" (
goto HELP
)
-set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%WINDOWS_ARCH%"
+set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%WINDOWS_ARCH%" %TESTS_CMAKE_ARGS%
if NOT EXIST %BUILD_DIR%\nul (
mkdir %BUILD_DIR%
)
@@ -282,6 +286,7 @@ goto EOF
echo - showhash ^(Show git hashes of source tree^)
echo.
echo Configuration options
+ echo - with_tests ^(enable building unit tests^)
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^)
diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg
index b54cadd40bc..e9c114ba1bd 100644
--- a/release/datafiles/blender_icons.svg
+++ b/release/datafiles/blender_icons.svg
@@ -14,7 +14,7 @@
height="640"
id="svg2"
sodipodi:version="0.32"
- inkscape:version="0.91 r13725"
+ inkscape:version="0.91 r"
version="1.0"
sodipodi:docname="blender_icons.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
@@ -28201,7 +28201,7 @@
xlink:href="#linearGradient37542-29"
id="linearGradient17610"
gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(-1,0,0,1,461.01011,-167)"
+ gradientTransform="matrix(-1,0,0,1,865.01833,131.0342)"
x1="392.0101"
y1="224.99998"
x2="392.0101"
@@ -28263,7 +28263,7 @@
xlink:href="#linearGradient37542-29-7"
id="linearGradient17610-0"
gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(-1,0,0,1,461.01011,-167)"
+ gradientTransform="translate(128.00098,130.98191)"
x1="392.0101"
y1="224.99998"
x2="392.0101"
@@ -28402,7 +28402,7 @@
x2="228.5468"
y1="118.91647"
x1="228.5468"
- gradientTransform="matrix(1.180548,0,0,0.90042534,265.27784,265.13062)"
+ gradientTransform="matrix(1.180548,0,0,0.90042534,265.83288,265.61628)"
gradientUnits="userSpaceOnUse"
id="linearGradient17838"
xlink:href="#linearGradient319-36-40-2"
@@ -28433,7 +28433,7 @@
x2="228.5468"
y1="118.91647"
x1="228.5468"
- gradientTransform="matrix(1.180548,0,0,0.90042534,223.26222,270.47438)"
+ gradientTransform="matrix(1.180548,0,0,0.90042534,223.81726,270.99473)"
gradientUnits="userSpaceOnUse"
id="linearGradient17872"
xlink:href="#linearGradient319-36-40-2-4"
@@ -29073,7 +29073,7 @@
xlink:href="#linearGradient27854-0-6-9"
id="linearGradient17162"
gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0,1,-1,0,782.48614,-14.46331)"
+ gradientTransform="matrix(0,1,-1,0,783.04118,-13.977664)"
x1="388.86502"
y1="244.02"
x2="391.43173"
@@ -29083,7 +29083,7 @@
xlink:href="#linearGradient37542-29-7-8"
id="linearGradient17165"
gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0,1,-1,0,782.48614,-14.46331)"
+ gradientTransform="matrix(0,1,-1,0,783.04118,-13.977664)"
x1="368.97806"
y1="249.99998"
x2="393.85385"
@@ -29113,7 +29113,7 @@
xlink:href="#linearGradient37542-29-1"
id="linearGradient17185"
gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0,-1,-1,0,740.48614,764.46331)"
+ gradientTransform="matrix(0,-1,-1,0,741.04118,764.98366)"
x1="409.93588"
y1="249.99998"
x2="385.11514"
@@ -31349,17 +31349,17 @@
objecttolerance="10000"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="1.274018"
- inkscape:cx="519.70993"
- inkscape:cy="325.90484"
+ inkscape:zoom="14.413868"
+ inkscape:cx="480.24726"
+ inkscape:cy="269.95478"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
- inkscape:window-width="1920"
- inkscape:window-height="1005"
- inkscape:window-x="-2"
- inkscape:window-y="27"
- inkscape:snap-nodes="false"
+ inkscape:window-width="1680"
+ inkscape:window-height="1020"
+ inkscape:window-x="0"
+ inkscape:window-y="30"
+ inkscape:snap-nodes="true"
inkscape:snap-bbox="true"
showguides="true"
inkscape:guide-bbox="true"
@@ -31369,14 +31369,16 @@
inkscape:snap-intersection-grid-guide="false"
inkscape:window-maximized="1"
inkscape:bbox-paths="false"
- inkscape:snap-global="false"
+ inkscape:snap-global="true"
inkscape:snap-bbox-midpoints="false"
- inkscape:snap-grids="true"
+ inkscape:snap-grids="false"
inkscape:snap-to-guides="false"
inkscape:snap-page="false"
units="pt"
inkscape:snap-center="false"
- inkscape:snap-object-midpoints="true">
+ inkscape:snap-object-midpoints="true"
+ inkscape:snap-midpoints="false"
+ inkscape:snap-others="false">
<inkscape:grid
type="xygrid"
id="grid17394"
@@ -88001,37 +88003,37 @@
<g
style="display:inline;enable-background:new"
id="ICON_COLLAPSEMENU"
- transform="translate(279.8665,506.92392)">
+ transform="translate(280,508)">
<rect
y="111"
x="103"
height="16"
width="16"
id="rect24489-7-4"
- style="opacity:0;fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ 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" />
<rect
style="fill:#ececec;fill-opacity:1;stroke:#141414;stroke-width:0.79452544;stroke-opacity:1"
id="rect29842"
- width="11.816368"
- height="2.1883197"
- x="105.18671"
- y="-116.88043"
+ width="11.209318"
+ height="2.1883163"
+ x="105.39484"
+ y="-116.60292"
transform="scale(1,-1)" />
<rect
- style="fill:#ececec;fill-opacity:1;stroke:#141414;stroke-width:0.79452544;stroke-opacity:1;display:inline;enable-background:new"
+ style="display:inline;fill:#ececec;fill-opacity:1;stroke:#141414;stroke-width:0.79452544;stroke-opacity:1;enable-background:new"
id="rect29842-4"
- width="11.816368"
- height="2.1883197"
- x="105.31538"
- y="-120.80865"
+ width="11.191971"
+ height="2.2056611"
+ x="105.41944"
+ y="-120.61786"
transform="scale(1,-1)" />
<rect
- style="fill:#ececec;fill-opacity:1;stroke:#141414;stroke-width:0.79452544;stroke-opacity:1;display:inline;enable-background:new"
+ style="display:inline;fill:#ececec;fill-opacity:1;stroke:#141414;stroke-width:0.79500002;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
id="rect29842-4-5"
- width="11.816368"
- height="2.1883197"
- x="105.41832"
- y="-124.71391"
+ width="11.22666"
+ height="2.2056642"
+ x="105.38363"
+ y="-124.60985"
transform="scale(1,-1)" />
</g>
<g
@@ -89360,17 +89362,18 @@
y="69" />
<g
id="g17605"
- transform="translate(-1.5467961,-0.48613592)">
+ transform="translate(-0.99177519,0.03419629)">
<path
- sodipodi:nodetypes="ccccccccccc"
+ style="fill:url(#linearGradient17610);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 472.51758,370.53516 -1.04688,0.0312 0.0371,9.96875 1.00977,0 3.95117,-3.70704 -5.3e-4,3.72852 3.1119,0 0,-10.01758 -3.1119,0 5.3e-4,3.73242 z"
+ transform="translate(-404.00822,-298.0342)"
+ id="path11011-6"
inkscape:connector-curvature="0"
- d="m 72.839729,82.521675 2.731705,0 0,-10.016275 -2.731705,0 L 72.84,76.59374 68.51011,72.5 67.4632,72.53125 67.5,82.49999 68.51011,82.5 72.84,78.43749 z"
- style="fill:url(#linearGradient17610);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path11011-6" />
+ sodipodi:nodetypes="ccccccccccc" />
<path
sodipodi:nodetypes="ccc"
style="fill:none;stroke:url(#linearGradient17612);stroke-width:0.91056824px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 73.7503,81.408784 0,-7.99274 0.910568,-6.3e-5"
+ d="m 73.368723,81.408784 0,-7.99274 1.292145,-6.3e-5"
id="path10830-6"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
inkscape:export-xdpi="90"
@@ -89397,17 +89400,18 @@
y="69" />
<g
id="g17605-3"
- transform="translate(-1.5467961,-0.48613592)">
+ transform="translate(-1.9392553,-0.11820549)">
<path
- sodipodi:nodetypes="ccccccccccc"
+ style="fill:url(#linearGradient17610-0);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 520.5,370.48242 -4.01758,3.80078 -6.6e-4,-3.79492 -3.04231,0 0,10.01563 3.04231,0 6.6e-4,-3.79297 4.01758,3.77148 1.01172,0 0.0371,-9.96875 z"
+ transform="matrix(-1,0,0,1,589.01109,-297.98191)"
+ id="path11011-6-2"
inkscape:connector-curvature="0"
- d="m 72.839729,82.521675 2.731705,0 0,-10.016275 -2.731705,0 L 72.84,76.59374 68.51011,72.5 67.4632,72.53125 67.5,82.49999 68.51011,82.5 72.84,78.43749 z"
- style="fill:url(#linearGradient17610-0);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path11011-6-2" />
+ sodipodi:nodetypes="ccccccccccc" />
<path
sodipodi:nodetypes="ccc"
style="fill:none;stroke:url(#linearGradient17612-5);stroke-width:0.91056824px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 74.660868,81.408784 0,-7.99274 -0.910568,-6.3e-5"
+ d="m 74.660868,81.408784 0,-7.99274 -1.220453,-6.3e-5"
id="path10830-6-2"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
inkscape:export-xdpi="90"
@@ -89432,16 +89436,16 @@
y="-546"
transform="matrix(0,-1,-1,0,0,0)" />
<path
+ style="fill:url(#linearGradient17165);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 533.51953,371.46094 0,3.04042 3.79492,5.9e-4 -3.77343,4.01953 0,1.01172 9.96875,0.0352 0.0312,-1.04688 -3.80274,-4.01953 3.79688,-5.9e-4 0,-3.04042 z"
id="path11011-6-2-1"
- style="fill:url(#linearGradient17165);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 532.96447,373.70707 0,-2.7317 10.01627,0 0,2.7317 -4.08834,-2.7e-4 4.09374,4.32989 -0.0312,1.04691 -9.96874,-0.0368 -1e-5,-1.01011 4.06251,-4.32989 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
<path
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc"
id="path11013-5-7-1"
- d="m 541.73615,378.0468 -3.75,-4 -3.75,4"
+ d="m 542.29119,378.53246 -3.75,-4 -3.75,4"
style="fill:none;stroke:url(#linearGradient17162);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
@@ -89449,8 +89453,8 @@
inkscape:export-xdpi="90"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
id="path10830-6-2-8"
- d="m 542.11634,371.83103 -8.26386,0 -6e-5,0.90043"
- style="fill:none;stroke:url(#linearGradient17838);stroke-width:0.92071104px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;display:inline;enable-background:new"
+ d="m 542.67138,372.31669 -8.26386,0 -6e-5,1.20843"
+ style="display:inline;fill:none;stroke:url(#linearGradient17838);stroke-width:0.92071104px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;enable-background:new"
sodipodi:nodetypes="ccc" />
</g>
<g
@@ -89464,16 +89468,16 @@
y="-504"
transform="matrix(0,1,-1,0,0,0)" />
<path
+ style="fill:url(#linearGradient17185);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 501.50977,371.4375 -9.96875,0.0352 0,1.01172 3.69336,3.93554 -3.71485,-0.005 0,3.13033 10.01563,0 0,-3.13033 -3.7168,0.007 3.72266,-3.9375 z"
id="path11011-6-8"
- style="fill:url(#linearGradient17185);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 490.96446,376.29293 0,2.7317 10.01628,0 0,-2.7317 -4.08834,2.7e-4 4.09374,-4.32989 -0.0312,-1.04691 -9.96874,0.0368 -10e-6,1.01011 4.06251,4.32989 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
<path
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc"
id="path11013-5-6"
- d="m 492.23615,371.9532 7.5,0"
+ d="m 492.79119,372.47355 7.5,0"
style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
@@ -89481,8 +89485,8 @@
inkscape:export-xdpi="90"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
id="path10830-6-2-8-8"
- d="m 500.10071,377.17478 -8.26386,0 -6e-5,0.90043"
- style="fill:none;stroke:url(#linearGradient17872);stroke-width:0.92071104px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;display:inline;enable-background:new"
+ d="m 500.65575,377.29722 -8.26386,0 -6e-5,1.29834"
+ style="display:inline;fill:none;stroke:url(#linearGradient17872);stroke-width:0.92071104px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;enable-background:new"
sodipodi:nodetypes="ccc" />
</g>
<g
diff --git a/release/datafiles/blender_icons16/icon16_collapsemenu.dat b/release/datafiles/blender_icons16/icon16_collapsemenu.dat
index fd16fadcc8b..246afa11c6c 100644
--- a/release/datafiles/blender_icons16/icon16_collapsemenu.dat
+++ b/release/datafiles/blender_icons16/icon16_collapsemenu.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_tria_down_bar.dat b/release/datafiles/blender_icons16/icon16_tria_down_bar.dat
index 3b734da490a..191f2075b1a 100644
--- a/release/datafiles/blender_icons16/icon16_tria_down_bar.dat
+++ b/release/datafiles/blender_icons16/icon16_tria_down_bar.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_tria_left_bar.dat b/release/datafiles/blender_icons16/icon16_tria_left_bar.dat
index 15826007e7b..e1ea5764367 100644
--- a/release/datafiles/blender_icons16/icon16_tria_left_bar.dat
+++ b/release/datafiles/blender_icons16/icon16_tria_left_bar.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_tria_right_bar.dat b/release/datafiles/blender_icons16/icon16_tria_right_bar.dat
index 75b180afbd7..ce9c3f78ad7 100644
--- a/release/datafiles/blender_icons16/icon16_tria_right_bar.dat
+++ b/release/datafiles/blender_icons16/icon16_tria_right_bar.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_tria_up_bar.dat b/release/datafiles/blender_icons16/icon16_tria_up_bar.dat
index b0730cafdd4..e51757d2650 100644
--- a/release/datafiles/blender_icons16/icon16_tria_up_bar.dat
+++ b/release/datafiles/blender_icons16/icon16_tria_up_bar.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_collapsemenu.dat b/release/datafiles/blender_icons32/icon32_collapsemenu.dat
index d84dd843436..788b4009542 100644
--- a/release/datafiles/blender_icons32/icon32_collapsemenu.dat
+++ b/release/datafiles/blender_icons32/icon32_collapsemenu.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_tria_down_bar.dat b/release/datafiles/blender_icons32/icon32_tria_down_bar.dat
index 7a00e79b711..ef6e86ba154 100644
--- a/release/datafiles/blender_icons32/icon32_tria_down_bar.dat
+++ b/release/datafiles/blender_icons32/icon32_tria_down_bar.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_tria_left_bar.dat b/release/datafiles/blender_icons32/icon32_tria_left_bar.dat
index 591b2e2b1bd..a1d48baf971 100644
--- a/release/datafiles/blender_icons32/icon32_tria_left_bar.dat
+++ b/release/datafiles/blender_icons32/icon32_tria_left_bar.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_tria_right_bar.dat b/release/datafiles/blender_icons32/icon32_tria_right_bar.dat
index 1dae635d600..4f687537658 100644
--- a/release/datafiles/blender_icons32/icon32_tria_right_bar.dat
+++ b/release/datafiles/blender_icons32/icon32_tria_right_bar.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_tria_up_bar.dat b/release/datafiles/blender_icons32/icon32_tria_up_bar.dat
index 1c7b3072f31..e6c5d5561cd 100644
--- a/release/datafiles/blender_icons32/icon32_tria_up_bar.dat
+++ b/release/datafiles/blender_icons32/icon32_tria_up_bar.dat
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject dc166057192ea882b5cc70484d4c8bacd7cb41b
+Subproject c93ed11a47b3016cf59711ec16de2e2e94c30e9
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 06dad53c80801e0e0919f086040e3d9c31bbd0a
+Subproject 371960484a38fc64e0a2635170a41a0d8ab2f6b
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 04af69be141a5757fc60b44cc1a5b72db524af3
+Subproject a8515cfdfe9a98127b592f36fcbe51b7e23b969
diff --git a/release/scripts/startup/bl_operators/freestyle.py b/release/scripts/startup/bl_operators/freestyle.py
index edda92284d2..fe3b00d54cd 100644
--- a/release/scripts/startup/bl_operators/freestyle.py
+++ b/release/scripts/startup/bl_operators/freestyle.py
@@ -62,31 +62,69 @@ class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator):
m = linestyle.alpha_modifiers[self.name]
else:
m = linestyle.thickness_modifiers[self.name]
- # Find the source object
+ # Find the reference object
if m.type == 'DISTANCE_FROM_CAMERA':
- source = scene.camera
+ ref = scene.camera
+ matrix_to_camera = ref.matrix_world.inverted()
elif m.type == 'DISTANCE_FROM_OBJECT':
if m.target is None:
self.report({'ERROR'}, "Target object not specified")
return {'CANCELLED'}
- source = m.target
+ ref = m.target
+ target_location = ref.location
else:
self.report({'ERROR'}, "Unexpected modifier type: " + m.type)
return {'CANCELLED'}
- # Find selected mesh objects
- selection = [ob for ob in scene.objects if ob.select and ob.type == 'MESH' and ob.name != source.name]
- if selection:
- # Compute the min/max distance between selected mesh objects and the source
+ # Find selected vertices in editmesh
+ ob = bpy.context.active_object
+ if ob.type == 'MESH' and ob.mode == 'EDIT' and ob.name != ref.name:
+ bpy.ops.object.mode_set(mode='OBJECT')
+ selected_verts = [v for v in bpy.context.active_object.data.vertices if v.select]
+ bpy.ops.object.mode_set(mode='EDIT')
+ # Compute the min/max distance from the reference to mesh vertices
min_dist = sys.float_info.max
max_dist = -min_dist
- for ob in selection:
- for vert in ob.data.vertices:
- dist = (ob.matrix_world * vert.co - source.location).length
+ if m.type == 'DISTANCE_FROM_CAMERA':
+ ob_to_cam = matrix_to_camera * ob.matrix_world
+ for vert in selected_verts:
+ # dist in the camera space
+ dist = (ob_to_cam * vert.co).length
+ min_dist = min(dist, min_dist)
+ max_dist = max(dist, max_dist)
+ elif m.type == 'DISTANCE_FROM_OBJECT':
+ for vert in selected_verts:
+ # dist in the world space
+ dist = (ob.matrix_world * vert.co - target_location).length
min_dist = min(dist, min_dist)
max_dist = max(dist, max_dist)
# Fill the Range Min/Max entries with the computed distances
m.range_min = min_dist
m.range_max = max_dist
+ return {'FINISHED'}
+ # Find selected mesh objects
+ selection = [ob for ob in scene.objects if ob.select and ob.type == 'MESH' and ob.name != ref.name]
+ if selection:
+ # Compute the min/max distance from the reference to mesh vertices
+ min_dist = sys.float_info.max
+ max_dist = -min_dist
+ if m.type == 'DISTANCE_FROM_CAMERA':
+ for ob in selection:
+ ob_to_cam = matrix_to_camera * ob.matrix_world
+ for vert in ob.data.vertices:
+ # dist in the camera space
+ dist = (ob_to_cam * vert.co).length
+ min_dist = min(dist, min_dist)
+ max_dist = max(dist, max_dist)
+ elif m.type == 'DISTANCE_FROM_OBJECT':
+ for ob in selection:
+ for vert in ob.data.vertices:
+ # dist in the world space
+ dist = (ob.matrix_world * vert.co - target_location).length
+ min_dist = min(dist, min_dist)
+ max_dist = max(dist, max_dist)
+ # Fill the Range Min/Max entries with the computed distances
+ m.range_min = min_dist
+ m.range_max = max_dist
return {'FINISHED'}
diff --git a/release/scripts/startup/bl_ui/properties_animviz.py b/release/scripts/startup/bl_ui/properties_animviz.py
index 11081232f12..046b5eb2aa5 100644
--- a/release/scripts/startup/bl_ui/properties_animviz.py
+++ b/release/scripts/startup/bl_ui/properties_animviz.py
@@ -86,8 +86,12 @@ class MotionPathButtonsPanel:
col = split.column()
col.label(text="Show:")
col.prop(mps, "show_frame_numbers", text="Frame Numbers")
+ if mpath is not None:
+ col.prop(mpath, "lines", text='Lines')
+ col.prop(mpath, "line_thickness", text='Thickness')
col = split.column()
+ col.label('')
col.prop(mps, "show_keyframe_highlight", text="Keyframes")
sub = col.column()
sub.enabled = mps.show_keyframe_highlight
@@ -95,6 +99,14 @@ class MotionPathButtonsPanel:
sub.prop(mps, "show_keyframe_action_all", text="+ Non-Grouped Keyframes")
sub.prop(mps, "show_keyframe_numbers", text="Keyframe Numbers")
+ # Customize path
+ if mpath is not None:
+ row = layout.row(align=True)
+ row.prop(mpath, "use_custom_color", text='', toggle=True, icon='COLOR')
+ sub = row.row(align=True)
+ sub.enabled = mpath.use_custom_color
+ sub.prop(mpath, "color", text='')
+
# FIXME: this panel still needs to be ported so that it will work correctly with animviz
class OnionSkinButtonsPanel:
diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py
index 98b7a76e541..ec061370fe5 100644
--- a/release/scripts/startup/bl_ui/properties_game.py
+++ b/release/scripts/startup/bl_ui/properties_game.py
@@ -469,8 +469,86 @@ class SceneButtonsPanel:
bl_context = "scene"
+class SCENE_PT_game_physics(SceneButtonsPanel, Panel):
+ bl_label = "Physics"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
+
+ @classmethod
+ def poll(cls, context):
+ scene = context.scene
+ return (scene.render.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ gs = context.scene.game_settings
+
+ layout.prop(gs, "physics_engine", text="Engine")
+ if gs.physics_engine != 'NONE':
+ layout.prop(gs, "physics_gravity", text="Gravity")
+
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Physics Steps:")
+ sub = col.column(align=True)
+ sub.prop(gs, "physics_step_max", text="Max")
+ sub.prop(gs, "physics_step_sub", text="Substeps")
+ col.prop(gs, "fps", text="FPS")
+
+ col = split.column()
+ col.label(text="Logic Steps:")
+ col.prop(gs, "logic_step_max", text="Max")
+
+ col = layout.column()
+ col.label(text="Physics Deactivation:")
+ sub = col.row(align=True)
+ sub.prop(gs, "deactivation_linear_threshold", text="Linear Threshold")
+ sub.prop(gs, "deactivation_angular_threshold", text="Angular Threshold")
+ sub = col.row()
+ sub.prop(gs, "deactivation_time", text="Time")
+
+ col = layout.column()
+ col.prop(gs, "use_occlusion_culling", text="Occlusion Culling")
+ sub = col.column()
+ sub.active = gs.use_occlusion_culling
+ sub.prop(gs, "occlusion_culling_resolution", text="Resolution")
+
+ else:
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Physics Steps:")
+ col.prop(gs, "fps", text="FPS")
+
+ col = split.column()
+ col.label(text="Logic Steps:")
+ col.prop(gs, "logic_step_max", text="Max")
+
+
+class SCENE_PT_game_physics_obstacles(SceneButtonsPanel, Panel):
+ bl_label = "Obstacle Simulation"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_GAME'}
+
+ @classmethod
+ def poll(cls, context):
+ scene = context.scene
+ return (scene.render.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ gs = context.scene.game_settings
+
+ layout.prop(gs, "obstacle_simulation", text="Type")
+ if gs.obstacle_simulation != 'NONE':
+ layout.prop(gs, "level_height")
+ layout.prop(gs, "show_obstacle_simulation")
+
+
class SCENE_PT_game_navmesh(SceneButtonsPanel, Panel):
- bl_label = "Navigation mesh"
+ bl_label = "Navigation Mesh"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_GAME'}
@@ -484,7 +562,7 @@ class SCENE_PT_game_navmesh(SceneButtonsPanel, Panel):
rd = context.scene.game_settings.recast_data
- layout.operator("mesh.navmesh_make", text="Build navigation mesh")
+ layout.operator("mesh.navmesh_make", text="Build Navigation Mesh")
col = layout.column()
col.label(text="Rasterization:")
@@ -656,83 +734,6 @@ class WORLD_PT_game_mist(WorldButtonsPanel, Panel):
layout.prop(world.mist_settings, "intensity", text="Minimum Intensity")
-class WORLD_PT_game_physics(WorldButtonsPanel, Panel):
- bl_label = "Physics"
- 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(self, context):
- layout = self.layout
-
- gs = context.scene.game_settings
-
- layout.prop(gs, "physics_engine", text="Engine")
- if gs.physics_engine != 'NONE':
- layout.prop(gs, "physics_gravity", text="Gravity")
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Physics Steps:")
- sub = col.column(align=True)
- sub.prop(gs, "physics_step_max", text="Max")
- sub.prop(gs, "physics_step_sub", text="Substeps")
- col.prop(gs, "fps", text="FPS")
-
- col = split.column()
- col.label(text="Logic Steps:")
- col.prop(gs, "logic_step_max", text="Max")
-
- col = layout.column()
- col.label(text="Physics Deactivation:")
- sub = col.row(align=True)
- sub.prop(gs, "deactivation_linear_threshold", text="Linear Threshold")
- sub.prop(gs, "deactivation_angular_threshold", text="Angular Threshold")
- sub = col.row()
- sub.prop(gs, "deactivation_time", text="Time")
-
- col = layout.column()
- col.prop(gs, "use_occlusion_culling", text="Occlusion Culling")
- sub = col.column()
- sub.active = gs.use_occlusion_culling
- sub.prop(gs, "occlusion_culling_resolution", text="Resolution")
-
- else:
- split = layout.split()
-
- col = split.column()
- col.label(text="Physics Steps:")
- col.prop(gs, "fps", text="FPS")
-
- col = split.column()
- col.label(text="Logic Steps:")
- col.prop(gs, "logic_step_max", text="Max")
-
-
-class WORLD_PT_game_physics_obstacles(WorldButtonsPanel, Panel):
- bl_label = "Obstacle simulation"
- 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(self, context):
- layout = self.layout
-
- gs = context.scene.game_settings
-
- layout.prop(gs, "obstacle_simulation", text="Type")
- if gs.obstacle_simulation != 'NONE':
- layout.prop(gs, "level_height")
- layout.prop(gs, "show_obstacle_simulation")
-
-
class DataButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
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 f8ee7c9a851..4529c127839 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -115,6 +115,12 @@ class GreasePencilDrawingToolsPanel:
row.operator("gpencil.draw", icon='LINE_DATA', text="Line").mode = 'DRAW_STRAIGHT'
row.operator("gpencil.draw", icon='MESH_DATA', text="Poly").mode = 'DRAW_POLY'
+ col.separator()
+
+ sub = col.column(align=True)
+ sub.operator("gpencil.blank_frame_add", icon='NEW')
+ sub.operator("gpencil.active_frames_delete_all", icon='X', text="Delete Frame(s)")
+
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")
@@ -227,12 +233,7 @@ class GreasePencilStrokeEditPanel:
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)
@@ -247,7 +248,57 @@ class GreasePencilStrokeEditPanel:
if is_3d_view:
layout.separator()
- layout.operator("gpencil.reproject")
+ layout.operator_menu_enum("gpencil.reproject", text="Reproject Strokes...", property="type")
+
+
+class GreasePencilInterpolatePanel:
+ bl_space_type = 'VIEW_3D'
+ bl_label = "Interpolate"
+ bl_category = "Grease Pencil"
+ bl_region_type = 'TOOLS'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ if context.gpencil_data is None:
+ return False
+ elif context.space_data.type != 'VIEW_3D':
+ return False
+
+ gpd = context.gpencil_data
+ return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ settings = context.tool_settings.gpencil_interpolate
+
+ col = layout.column(align=True)
+ col.operator("gpencil.interpolate", text="Interpolate")
+ col.operator("gpencil.interpolate_sequence", text="Sequence")
+ col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns")
+
+ col = layout.column(align=True)
+ col.label(text="Options:")
+ col.prop(settings, "interpolate_all_layers")
+ col.prop(settings, "interpolate_selected_only")
+
+ col = layout.column(align=True)
+ col.label(text="Sequence Options:")
+ col.prop(settings, "type")
+ if settings.type == 'CUSTOM':
+ box = layout.box()
+ # TODO: Options for loading/saving curve presets?
+ box.template_curve_mapping(settings, "interpolation_curve", brush=True)
+ elif settings.type != 'LINEAR':
+ col.prop(settings, "easing")
+
+ if settings.type == 'BACK':
+ layout.prop(settings, "back")
+ elif setting.type == 'ELASTIC':
+ sub = layout.column(align=True)
+ sub.prop(settings, "amplitude")
+ sub.prop(settings, "period")
class GreasePencilBrushPanel:
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index 780dc4cf982..2a085b8aada 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -306,7 +306,7 @@ class INFO_MT_help(Menu):
layout.operator(
"wm.url_open", text="Manual", icon='HELP',
- ).url = "https://www.blender.org/manual"
+ ).url = "https://docs.blender.org/manual/en/dev/"
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]
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index 708db2eec8d..6f7c535fe21 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -93,7 +93,8 @@ class OUTLINER_MT_view(Menu):
layout.separator()
layout.operator("outliner.show_active")
- layout.operator("outliner.show_one_level")
+ layout.operator("outliner.show_one_level", text="Show One Level")
+ layout.operator("outliner.show_one_level", text="Hide One Level").open = False
layout.operator("outliner.show_hierarchy")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 26136a8e024..6bb516cf929 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -435,15 +435,9 @@ class SEQUENCER_MT_strip(Menu):
layout.operator("sequencer.crossfade_sounds")
layout.separator()
-
layout.operator("sequencer.meta_make")
layout.operator("sequencer.meta_separate")
- #if (ed && (ed->metastack.first || (ed->act_seq && ed->act_seq->type == SEQ_META))) {
- # uiItemS(layout);
- # uiItemO(layout, NULL, 0, "sequencer.meta_toggle");
- #}
-
layout.separator()
layout.operator("sequencer.reload", text="Reload Strips")
layout.operator("sequencer.reload", text="Reload Strips and Adjust Length").adjust_length = True
@@ -497,6 +491,7 @@ class SequencerButtonsPanel_Output:
class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel):
bl_label = "Edit Strip"
+ bl_category = "Strip"
def draw(self, context):
layout = self.layout
@@ -563,6 +558,7 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel):
class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
bl_label = "Effect Strip"
+ bl_category = "Strip"
@classmethod
def poll(cls, context):
@@ -701,6 +697,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
bl_label = "Strip Input"
+ bl_category = "Strip"
@classmethod
def poll(cls, context):
@@ -795,6 +792,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
bl_label = "Sound"
+ bl_category = "Strip"
@classmethod
def poll(cls, context):
@@ -848,6 +846,7 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
bl_label = "Scene"
+ bl_category = "Strip"
@classmethod
def poll(cls, context):
@@ -894,6 +893,7 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
bl_label = "Mask"
+ bl_category = "Strip"
@classmethod
def poll(cls, context):
@@ -923,6 +923,7 @@ class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
bl_label = "Filter"
+ bl_category = "Strip"
@classmethod
def poll(cls, context):
@@ -977,6 +978,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
bl_label = "Proxy/Timecode"
+ bl_category = "Strip"
@classmethod
def poll(cls, context):
@@ -1109,6 +1111,7 @@ class SEQUENCER_PT_view_safe_areas(SequencerButtonsPanel_Output, Panel):
class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
bl_label = "Modifiers"
+ bl_category = "Modifiers"
def draw(self, context):
layout = self.layout
@@ -1211,6 +1214,7 @@ class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "scene.sequence_editor.active_strip"
_property_type = (bpy.types.Sequence,)
+ bl_category = "Strip"
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 3eb76a3b0f9..60e86d7544d 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -22,6 +22,7 @@ from bpy.types import Menu, Panel, UIList
from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
+ GreasePencilInterpolatePanel,
GreasePencilStrokeSculptPanel,
GreasePencilBrushPanel,
GreasePencilBrushCurvesPanel
@@ -1963,6 +1964,11 @@ class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
bl_space_type = 'VIEW_3D'
+# Grease Pencil stroke interpolation tools
+class VIEW3D_PT_tools_grease_pencil_interpolate(GreasePencilInterpolatePanel, Panel):
+ bl_space_type = 'VIEW_3D'
+
+
# Grease Pencil stroke sculpting tools
class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
bl_space_type = 'VIEW_3D'
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 69358302782..e915aa5bb72 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -145,6 +145,7 @@ shader_node_categories = [
NodeItem("ShaderNodeMaterial"),
NodeItem("ShaderNodeCameraData"),
NodeItem("ShaderNodeFresnel"),
+ NodeItem("ShaderNodeLayerWeight"),
NodeItem("ShaderNodeLampData"),
NodeItem("ShaderNodeValue"),
NodeItem("ShaderNodeRGB"),
diff --git a/release/scripts/templates_py/addon_add_object.py b/release/scripts/templates_py/addon_add_object.py
index d294838d3a2..56e6e79b94f 100644
--- a/release/scripts/templates_py/addon_add_object.py
+++ b/release/scripts/templates_py/addon_add_object.py
@@ -69,7 +69,7 @@ def add_object_button(self, context):
# This allows you to right click on a button and link to the manual
def add_object_manual_map():
- url_manual_prefix = "https://www.blender.org/manual/"
+ url_manual_prefix = "https://docs.blender.org/manual/en/dev/"
url_manual_mapping = (
("bpy.ops.mesh.add_object", "editors/3dview/object"),
)
diff --git a/release/text/readme.html b/release/text/readme.html
index 8e08a8ba027..45bff37b025 100644
--- a/release/text/readme.html
+++ b/release/text/readme.html
@@ -104,7 +104,7 @@ Full release log <a href="http://wiki.blender.org/index.php/Dev:Ref/Release_Note
<span class="s4">wiki.blender.org/index.php/Dev:Ref/Release_Notes/BLENDER_VERSION</span></a><br>
Tutorials <a href="http://www.blender.org/support/tutorials/">
<span class="s4">www.blender.org/support/tutorials/</span></a> <br>
-Manual <a href="http://www.blender.org/manual"><span class="s4">www.blender.org/manual</span></a><br>
+Manual <a href="https://docs.blender.org/manual/en/dev/"><span class="s4">https://docs.blender.org/manual/en/dev/</span></a><br>
User Forum <a href="http://www.blenderartists.org/">
<span class="s4">www.blenderartists.org</span></a><br>
IRC <a href="irc://irc.freenode.net/#blenderchat">
diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt
index ad85f79ef2e..a6e0be6a7f3 100644
--- a/source/blender/alembic/CMakeLists.txt
+++ b/source/blender/alembic/CMakeLists.txt
@@ -39,14 +39,10 @@ set(INC
set(INC_SYS
${ALEMBIC_INCLUDE_DIRS}
+ ${BOOST_INCLUDE_DIR}
${HDF5_INCLUDE_DIRS}
${OPENEXR_INCLUDE_DIRS}
)
-if(APPLE OR WIN32)
- list(APPEND INC_SYS
- ${BOOST_INCLUDE_DIR}
- )
-endif()
set(SRC
intern/abc_archive.cc
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index 133168fccf2..b6f5ffbb092 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -98,6 +98,10 @@ void BLF_thumb_preview(
blf_font_size(font, (unsigned int)MAX2(font_size_min, font_size_curr), dpi);
+ /* font->glyph_cache remains NULL if blf_font_size() failed to set font size */
+ if (!font->glyph_cache)
+ break;
+
/* decrease font size each time */
font_size_curr -= (font_size_curr / font_shrink);
font_shrink += 1;
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index 8756f73df72..3ce08a14177 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -116,13 +116,4 @@ void BKE_defvert_extract_vgroup_to_polyweights(
struct MDeformVert *dvert, const int defgroup, const int num_verts, struct MLoop *loops, const int num_loops,
struct MPoly *polys, const int num_polys, float *r_weights, const bool invert_vgroup);
-/* utility function, note that MAX_VGROUP_NAME chars is the maximum string length since its only
- * used with defgroups currently */
-
-void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char base[MAX_VGROUP_NAME], char ext[MAX_VGROUP_NAME]);
-void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char base[MAX_VGROUP_NAME], char ext[MAX_VGROUP_NAME]);
-
-void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME],
- const bool strip_number);
-
#endif /* __BKE_DEFORM_H__ */
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 2d9c35f7fd0..72ae2cf4efa 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -86,7 +86,7 @@ bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const boo
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
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_expand_local(struct Main *bmain, 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);
@@ -105,6 +105,9 @@ void BKE_main_free(struct Main *mainvar);
void BKE_main_lock(struct Main *bmain);
void BKE_main_unlock(struct Main *bmain);
+void BKE_main_relations_create(struct Main *bmain);
+void BKE_main_relations_free(struct Main *bmain);
+
struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img);
struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
void BKE_main_thumbnail_create(struct Main *bmain);
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index a7470107c24..1258e2fa72e 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -36,25 +36,28 @@ struct Main;
/* Tips for the callback for cases it's gonna to modify the pointer. */
enum {
- IDWALK_NOP = 0,
- IDWALK_NEVER_NULL = (1 << 0),
- IDWALK_NEVER_SELF = (1 << 1),
+ IDWALK_CB_NOP = 0,
+ IDWALK_CB_NEVER_NULL = (1 << 0),
+ IDWALK_CB_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),
+ IDWALK_CB_INDIRECT_USAGE = (1 << 2),
+
+ /** That ID is used as mere sub-data by its owner
+ * (only case currently: those f***ing nodetrees in materials etc.).
+ * This means callback shall not *do* anything, only use this as informative data if it needs it. */
+ IDWALK_CB_PRIVATE = (1 << 3),
/**
* Adjusts #ID.us reference-count.
* \note keep in sync with 'newlibadr_us' use in readfile.c
*/
- IDWALK_USER = (1 << 8),
- /**
- * Ensure #ID.us is at least 1 on use.
- */
- IDWALK_USER_ONE = (1 << 9),
+ IDWALK_CB_USER = (1 << 8),
+ /** Ensure #ID.us is at least 1 on use. */
+ IDWALK_CB_USER_ONE = (1 << 9),
};
enum {
@@ -68,17 +71,19 @@ enum {
*
* \return a set of flags to control further iteration (0 to keep going).
*/
-typedef int (*LibraryIDLinkCallback) (void *user_data, struct ID *id_self, struct ID **id_pointer, int cd_flag);
+typedef int (*LibraryIDLinkCallback) (void *user_data, struct ID *id_self, struct ID **id_pointer, int cb_flag);
/* Flags for the foreach function itself. */
enum {
+ IDWALK_NOP = 0,
IDWALK_READONLY = (1 << 0),
IDWALK_RECURSE = (1 << 1), /* Also implies IDWALK_READONLY. */
};
/* Loop over all of the ID's this datablock links to. */
-void BKE_library_foreach_ID_link(struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
-void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cd_flag);
+void BKE_library_foreach_ID_link(
+ struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
+void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cb_flag);
int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index a4f5c425282..387045878f3 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -51,6 +51,8 @@ extern "C" {
struct EvaluationContext;
struct Library;
struct MainLock;
+struct GHash;
+struct BLI_mempool;
/* Blender thumbnail, as written on file (width, height, and data as char RGBA). */
/* We pack pixel data after that struct. */
@@ -59,6 +61,22 @@ typedef struct BlendThumbnail {
char rect[0];
} BlendThumbnail;
+/* Structs caching relations between data-blocks in a given Main. */
+typedef struct MainIDRelationsEntry {
+ struct MainIDRelationsEntry *next;
+ /* WARNING! for user_to_used, that pointer is really an ID** one, but for used_to_user, it’s only an ID* one! */
+ struct ID **id_pointer;
+ int usage_flag; /* Using IDWALK_ enums, in BKE_library_query.h */
+} MainIDRelationsEntry;
+
+typedef struct MainIDRelations {
+ struct GHash *id_user_to_used;
+ struct GHash *id_used_to_user;
+
+ /* Private... */
+ struct BLI_mempool *entry_pool;
+} MainIDRelations;
+
typedef struct Main {
struct Main *next, *prev;
char name[1024]; /* 1024 = FILE_MAX */
@@ -111,6 +129,11 @@ typedef struct Main {
/* Evaluation context used by viewport */
struct EvaluationContext *eval_ctx;
+ /* Must be generated, used and freed by same code - never assume this is valid data unless you know
+ * when, who and how it was created.
+ * Used by code doing a lot of remapping etc. at once to speed things up. */
+ struct MainIDRelations *relations;
+
struct MainLock *lock;
} Main;
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index f6c08909d23..b241b5ca5b7 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -106,8 +106,8 @@ typedef enum {
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
-typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cd_flag);
-typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cd_flag);
+typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
typedef void (*TexWalkFunc)(void *userData, struct Object *ob, struct ModifierData *md, const char *propname);
typedef enum ModifierApplyFlag {
@@ -273,7 +273,7 @@ typedef struct ModifierTypeInfo {
*
* This function is optional.
*/
- /* TODO(sergey): Remove once we finalyl switched to the new depsgraph. */
+ /* TODO(sergey): Remove once we finally switched to the new depsgraph. */
void (*updateDepsgraph)(struct ModifierData *md,
struct Main *bmain,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index cf07a178fe8..d812ab832a1 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -136,14 +136,9 @@ void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float
/* possibly belong in own moduke? */
struct BoundBox *BKE_boundbox_alloc_unit(void);
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3]);
-bool BKE_boundbox_ray_hit_check(
- const struct BoundBox *bb,
- const float ray_start[3], const float ray_normal[3],
- float *r_lambda);
void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]);
void BKE_boundbox_calc_size_aabb(const struct BoundBox *bb, float r_size[3]);
void BKE_boundbox_minmax(const struct BoundBox *bb, float obmat[4][4], float r_min[3], float r_max[3]);
-void BKE_boundbox_scale(struct BoundBox *bb_dst, const struct BoundBox *bb_src, float scale);
struct BoundBox *BKE_boundbox_ensure_minimum_dimensions(
struct BoundBox *bb, struct BoundBox *bb_temp, const float epsilon);
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index b3e3968ca9b..e5967be0bc7 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -384,7 +384,7 @@ void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleDa
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);
+typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cb_flag);
void BKE_particlesystem_id_loop(struct ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata);
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 965a97f08ba..443c3b2b5b2 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -53,7 +53,7 @@ struct RigidBodyOb *BKE_rigidbody_copy_object(struct Object *ob);
struct RigidBodyCon *BKE_rigidbody_copy_constraint(struct Object *ob);
/* Callback format for performing operations on ID-pointers for rigidbody world. */
-typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cd_flag);
+typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cb_flag);
void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata);
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
index a504f1bac3d..1579a0c7bb3 100644
--- a/source/blender/blenkernel/BKE_sca.h
+++ b/source/blender/blenkernel/BKE_sca.h
@@ -77,9 +77,9 @@ void sca_move_controller(struct bController *cont_to_move, struct Object *ob, in
void sca_move_actuator(struct bActuator *act_to_move, struct Object *ob, int move_up);
/* Callback format for performing operations on ID-pointers for sensors/controllers/actuators. */
-typedef void (*SCASensorIDFunc)(struct bSensor *sensor, struct ID **idpoin, void *userdata, int cd_flag);
-typedef void (*SCAControllerIDFunc)(struct bController *controller, struct ID **idpoin, void *userdata, int cd_flag);
-typedef void (*SCAActuatorIDFunc)(struct bActuator *actuator, struct ID **idpoin, void *userdata, int cd_flag);
+typedef void (*SCASensorIDFunc)(struct bSensor *sensor, struct ID **idpoin, void *userdata, int cb_flag);
+typedef void (*SCAControllerIDFunc)(struct bController *controller, struct ID **idpoin, void *userdata, int cb_flag);
+typedef void (*SCAActuatorIDFunc)(struct bActuator *actuator, struct ID **idpoin, void *userdata, int cb_flag);
void BKE_sca_sensors_id_loop(struct ListBase *senslist, SCASensorIDFunc func, void *userdata);
void BKE_sca_controllers_id_loop(struct ListBase *contlist, SCAControllerIDFunc func, void *userdata);
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 1f937d837b4..160adcc3988 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -2215,6 +2215,12 @@ static void mesh_calc_modifiers(
}
}
+ /* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them,
+ * as they are used by display code when available (i.e. even if autosmooth is disabled). */
+ if (!do_loop_normals && CustomData_has_layer(&finaldm->loopData, CD_NORMAL)) {
+ CustomData_free_layers(&finaldm->loopData, CD_NORMAL, finaldm->numLoopData);
+ }
+
#ifdef WITH_GAMEENGINE
/* NavMesh - this is a hack but saves having a NavMesh modifier */
if ((ob->gameflag & OB_NAVMESH) && (finaldm->type == DM_TYPE_CDDM)) {
@@ -2550,6 +2556,15 @@ static void editbmesh_calc_modifiers(
/* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */
if (!do_loop_normals) {
dm_ensure_display_normals(*r_final);
+
+ /* Some modifiers, like datatransfer, may generate those data, we do not want to keep them,
+ * as they are used by display code when available (i.e. even if autosmooth is disabled). */
+ if (CustomData_has_layer(&(*r_final)->loopData, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_final)->loopData, CD_NORMAL, (*r_final)->numLoopData);
+ }
+ if (r_cage && CustomData_has_layer(&(*r_cage)->loopData, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_cage)->loopData, CD_NORMAL, (*r_cage)->numLoopData);
+ }
}
/* add an orco layer if needed */
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index dcbb667adca..1e33fe4ab46 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -44,6 +44,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -494,7 +495,7 @@ bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name)
{
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, name, false);
+ BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
if (!STREQ(name_flip, name)) {
return BKE_pose_channel_find_name(pose, name_flip);
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index 7d3d12ac112..2f65e71c6d2 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -201,7 +201,15 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec
mpath->flag |= MOTIONPATH_FLAG_BHEAD;
else
mpath->flag &= ~MOTIONPATH_FLAG_BHEAD;
-
+
+ /* set default custom values */
+ mpath->color[0] = 1.0; /* Red */
+ mpath->color[1] = 0.0;
+ mpath->color[2] = 0.0;
+
+ mpath->line_thickness = 1;
+ mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
+
/* allocate a cache */
mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts");
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 21279392392..0b637355ecf 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -43,6 +43,7 @@
#include "BLI_alloca.h"
#include "BLI_dynstr.h"
#include "BLI_listbase.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 2b333941c6e..0287d6ae9ca 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -87,6 +87,7 @@ bArmature *BKE_armature_add(Main *bmain, const char *name)
arm->deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE;
arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */
arm->layer = 1;
+ arm->ghostsize = 1;
return arm;
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 0d509ecea06..57b707a31d3 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -239,7 +239,7 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data(bmain, &brush->id);
- BKE_id_expand_local(&brush->id);
+ BKE_id_expand_local(bmain, &brush->id);
/* enable fake user by default */
id_fake_user_set(&brush->id);
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index deeb35bd880..3dce08eb756 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -215,7 +215,9 @@ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
if (cache_file == mcmd->cache_file) {
#ifdef WITH_ALEMBIC
- CacheReader_free(mcmd->reader);
+ if (mcmd->reader != NULL) {
+ CacheReader_free(mcmd->reader);
+ }
#endif
mcmd->reader = NULL;
mcmd->object_path[0] = '\0';
@@ -231,7 +233,9 @@ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
if (cache_file == data->cache_file) {
#ifdef WITH_ALEMBIC
- CacheReader_free(data->reader);
+ if (data->reader != NULL) {
+ CacheReader_free(data->reader);
+ }
#endif
data->reader = NULL;
data->object_path[0] = '\0';
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index cb74dbcd8d1..58ad171ee20 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -42,7 +42,7 @@
#include "BLI_math.h"
#include "BLI_kdopbvh.h"
#include "BLI_utildefines.h"
-
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
#include "DNA_armature_types.h"
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 612f1f477e1..98d37fb07bf 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -45,8 +45,9 @@
#include "DNA_ID.h"
#include "BLI_utildefines.h"
-#include "BLI_string.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_mempool.h"
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 7052e0a7d25..13b1aab5e1c 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -45,8 +45,8 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -509,7 +509,7 @@ int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default)
if (use_default)
map[i] = i;
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_num = defgroup_name_index(ob, name_flip);
@@ -545,7 +545,7 @@ int *defgroup_flip_map_single(Object *ob, int *flip_map_len, const bool use_defa
dg = BLI_findlink(&ob->defbase, defgroup);
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_num = defgroup_name_index(ob, name_flip);
@@ -566,7 +566,7 @@ int defgroup_flip_index(Object *ob, int index, const bool use_default)
if (dg) {
char name_flip[sizeof(dg->name)];
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_index = defgroup_name_index(ob, name_flip);
@@ -606,185 +606,6 @@ void defgroup_unique_name(bDeformGroup *dg, Object *ob)
BLI_uniquename_cb(defgroup_unique_check, &data, DATA_("Group"), '.', dg->name, sizeof(dg->name));
}
-static bool is_char_sep(const char c)
-{
- return ELEM(c, '.', ' ', '-', '_');
-}
-
-/**
- * based on `BLI_split_dirfile()` / `os.path.splitext()`,
- * `"a.b.c"` -> (`"a.b"`, `".c"`).
- */
-void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME], char suf[MAX_VGROUP_NAME])
-{
- size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
- size_t i;
-
- body[0] = suf[0] = '\0';
-
- for (i = len; i > 0; i--) {
- if (is_char_sep(string[i])) {
- BLI_strncpy(body, string, i + 1);
- BLI_strncpy(suf, string + i, (len + 1) - i);
- return;
- }
- }
-
- memcpy(body, string, len + 1);
-}
-
-/**
- * `"a.b.c"` -> (`"a."`, `"b.c"`)
- */
-void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char pre[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME])
-{
- size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
- size_t i;
-
- body[0] = pre[0] = '\0';
-
- for (i = 1; i < len; i++) {
- if (is_char_sep(string[i])) {
- i++;
- BLI_strncpy(pre, string, i + 1);
- BLI_strncpy(body, string + i, (len + 1) - i);
- return;
- }
- }
-
- BLI_strncpy(body, string, len);
-}
-
-/**
- * Finds the best possible flipped name. For renaming; check for unique names afterwards.
- *
- * if strip_number: removes number extensions
- *
- * \note don't use sizeof() for 'name' or 'from_name'.
- */
-void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME],
- const bool strip_number)
-{
- int len;
- char prefix[MAX_VGROUP_NAME] = ""; /* The part before the facing */
- char suffix[MAX_VGROUP_NAME] = ""; /* The part after the facing */
- char replace[MAX_VGROUP_NAME] = ""; /* The replacement string */
- char number[MAX_VGROUP_NAME] = ""; /* The number extension string */
- char *index = NULL;
- bool is_set = false;
-
- /* always copy the name, since this can be called with an uninitialized string */
- BLI_strncpy(name, from_name, MAX_VGROUP_NAME);
-
- len = BLI_strnlen(from_name, MAX_VGROUP_NAME);
- if (len < 3) {
- /* we don't do names like .R or .L */
- return;
- }
-
- /* We first check the case with a .### extension, let's find the last period */
- if (isdigit(name[len - 1])) {
- index = strrchr(name, '.'); // last occurrence
- if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever!
- if (strip_number == false) {
- BLI_strncpy(number, index, sizeof(number));
- }
- *index = 0;
- len = BLI_strnlen(name, MAX_VGROUP_NAME);
- }
- }
-
- BLI_strncpy(prefix, name, sizeof(prefix));
-
- /* first case; separator . - _ with extensions r R l L */
- if ((len > 1) && is_char_sep(name[len - 2])) {
- is_set = true;
- switch (name[len - 1]) {
- case 'l':
- prefix[len - 1] = 0;
- strcpy(replace, "r");
- break;
- case 'r':
- prefix[len - 1] = 0;
- strcpy(replace, "l");
- break;
- case 'L':
- prefix[len - 1] = 0;
- strcpy(replace, "R");
- break;
- case 'R':
- prefix[len - 1] = 0;
- strcpy(replace, "L");
- break;
- default:
- is_set = false;
- }
- }
-
- /* case; beginning with r R l L, with separator after it */
- if (!is_set && is_char_sep(name[1])) {
- is_set = true;
- switch (name[0]) {
- case 'l':
- strcpy(replace, "r");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'r':
- strcpy(replace, "l");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'L':
- strcpy(replace, "R");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'R':
- strcpy(replace, "L");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- default:
- is_set = false;
- }
- }
-
- if (!is_set && len > 5) {
- /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
- if (((index = BLI_strcasestr(prefix, "right")) == prefix) ||
- (index == prefix + len - 5))
- {
- is_set = true;
- if (index[0] == 'r') {
- strcpy(replace, "left");
- }
- else {
- strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
- }
- *index = 0;
- BLI_strncpy(suffix, index + 5, sizeof(suffix));
- }
- else if (((index = BLI_strcasestr(prefix, "left")) == prefix) ||
- (index == prefix + len - 4))
- {
- is_set = true;
- if (index[0] == 'l') {
- strcpy(replace, "right");
- }
- else {
- strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
- }
- *index = 0;
- BLI_strncpy(suffix, index + 4, sizeof(suffix));
- }
- }
-
- (void)is_set; /* quiet warning */
-
- BLI_snprintf(name, MAX_VGROUP_NAME, "%s%s%s%s", prefix, replace, suffix, number);
-}
-
float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
{
MDeformWeight *dw = defvert_find_index(dvert, defgroup);
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index a8341939692..294a4ce76b7 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -2563,7 +2563,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
}
static void dag_id_flush_update__isDependentTexture(
- void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
+ void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cb_flag))
{
struct { ID *id; bool is_dependent; } *data = userData;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 1d198e36e05..dc9f3b57f1f 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_string_utils.h"
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -215,6 +216,7 @@ typedef struct ImgSeqFormatData {
/* adjacency data flags */
#define ADJ_ON_MESH_EDGE (1 << 0)
+#define ADJ_BORDER_PIXEL (1 << 1)
typedef struct PaintAdjData {
int *n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */
@@ -222,6 +224,8 @@ typedef struct PaintAdjData {
int *n_num; /* num of neighs for each point */
int *flags; /* vertex adjacency flags */
int total_targets; /* size of n_target */
+ int *border; /* indices of border pixels (only for texture paint) */
+ int total_border; /* size of border */
} PaintAdjData;
/***************************** General Utils ******************************/
@@ -822,6 +826,8 @@ static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
MEM_freeN(data->adj_data->n_target);
if (data->adj_data->flags)
MEM_freeN(data->adj_data->flags);
+ if (data->adj_data->border)
+ MEM_freeN(data->adj_data->border);
MEM_freeN(data->adj_data);
data->adj_data = NULL;
}
@@ -1298,6 +1304,8 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
ad->total_targets = neigh_points;
+ ad->border = NULL;
+ ad->total_border = 0;
/* in case of allocation error, free memory */
if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
@@ -2295,6 +2303,36 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
#undef JITTER_SAMPLES
+static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri, const MLoopUV *mloopuv, int tri_index, const float point[2])
+{
+ float min_distance = FLT_MAX;
+
+ for (int i = 0; i < 3; i++) {
+ const float dist_squared = dist_squared_to_line_segment_v2(
+ point,
+ mloopuv[mlooptri[tri_index].tri[(i + 0)]].uv,
+ mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]].uv
+ );
+
+ if (dist_squared < min_distance)
+ min_distance = dist_squared;
+ }
+
+ return min_distance;
+}
+
+typedef struct DynamicPaintFindIslandBorderData {
+ const MeshElemMap *vert_to_looptri_map;
+ int w, h, px, py;
+
+ int best_index;
+ float best_weight;
+} DynamicPaintFindIslandBorderData;
+
+static void dynamic_paint_find_island_border(
+ const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
+ int tri_index, const float pixel[2], int in_edge, int depth);
+
/* Tries to find the neighboring pixel in given (uv space) direction.
* Result is used by effect system to move paint on the surface.
*
@@ -2345,167 +2383,162 @@ static int dynamic_paint_find_neighbour_pixel(
* TODO: Implement something more accurate / optimized?
*/
{
- const MLoop *mloop = data->mloop;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
-
- /* Get closest edge to that subpixel on UV map */
+ DynamicPaintFindIslandBorderData bdata = {
+ .vert_to_looptri_map = vert_to_looptri_map,
+ .w = w, .h = h, .px = px, .py = py,
+ .best_index = NOT_FOUND, .best_weight = 1.0f
+ };
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;
-
- 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
- */
+ /* Do a small recursive search for the best island edge. */
+ dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5);
- /* 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;
- }
+ return bdata.best_index;
+ }
+}
- /*
- * Now find another face that is linked to that edge
- */
- target_tri = -1;
+static void dynamic_paint_find_island_border(
+ const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
+ int tri_index, const float pixel[2], int in_edge, int depth)
+{
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
- /* 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;
+ const unsigned int *loop_idx = mlooptri[tri_index].tri;
- BLI_assert(ELEM(e1_index, v0, v1, v2));
+ /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
+ for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
+ /* but not the edge we have just recursed through */
+ if (edge_idx == in_edge)
+ continue;
- if (ELEM(e2_index, v0, v1, v2)) {
- if (lt_index == cPoint->tri_index)
- continue;
+ float uv0[2], uv1[2], uv2[2];
- target_tri = lt_index;
+ copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]].uv);
+ copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]].uv);
+ copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]].uv);
- /* 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;
- }
- }
+ /* Verify the target point is on the opposite side of the edge from the third triangle
+ * vertex, to ensure that we always move closer to the goal point. */
+ const float sidep = line_point_side_v2(uv0, uv1, pixel);
+ const float side2 = line_point_side_v2(uv0, uv1, uv2);
- /* If none found pixel is on mesh edge */
- if (target_tri == -1)
- return ON_MESH_EDGE;
+ if (side2 == 0.0f)
+ continue;
- /*
- * 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;
+ /* Hack: allow all edges of the original triangle */
+ const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) || (sidep > 0 && side2 < 0);
- //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]);
+ /* Allow exactly on edge for the non-recursive case */
+ if (!correct_side && sidep != 0.0f)
+ 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])))
- {
- final_index = x + w * y;
+ /* Now find another face that is linked to that edge. */
+ const int vert0 = mloop[loop_idx[(edge_idx + 0)]].v;
+ const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v;
+
+ /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
+ const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
+
+ bool found_other = false;
+ int target_tri = -1;
+ int target_edge = -1;
+
+ float ouv0[2], ouv1[2];
+
+ for (int i = 0; i < map->count && !found_other; i++) {
+ const int lt_index = map->indices[i];
+
+ if (lt_index == tri_index)
+ continue;
+
+ const unsigned int *other_loop_idx = mlooptri[lt_index].tri;
+
+ /* Check edges for match, looping in the same order as the outer loop. */
+ for (int j = 0; j < 3; j++)
+ {
+ const int overt0 = mloop[other_loop_idx[(j + 0)]].v;
+ const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v;
+
+ /* Allow for swapped vertex order */
+ if (overt0 == vert0 && overt1 == vert1) {
+ found_other = true;
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+ else if (overt0 == vert1 && overt1 == vert0) {
+ found_other = true;
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+
+ if (found_other) {
+ target_tri = lt_index;
+ target_edge = j;
+ break;
+ }
+ }
+ }
- /* If not an active pixel, bail out */
- if (tempPoints[final_index].tri_index == -1)
- return NOT_FOUND;
+ if (!found_other) {
+ if (bdata->best_index < 0)
+ bdata->best_index = ON_MESH_EDGE;
- /* 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;
+ continue;
+ }
- /* If we ended up to our origin point */
- if (final_index == (px + w * py))
- return NOT_FOUND;
+ /* If this edge is connected in UV space too, recurse */
+ if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) {
+ if (depth > 0 && correct_side) {
+ dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1);
}
- return final_index;
+ continue;
}
+ /* Otherwise try to map to the other side of the edge.
+ * First check if there already is a better solution. */
+ const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1);
+
+ if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight)
+ continue;
+
/*
* 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);
+ float closest_point[2], dir_vec[2], tgt_pixel[2];
- sub_v2_v2v2(
- dir_vec,
- mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
- mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+ float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1);
+ CLAMP(lambda, 0.0f, 1.0f);
- mul_v2_fl(dir_vec, lambda);
+ sub_v2_v2v2(dir_vec, ouv1, ouv0);
+ madd_v2_v2v2fl(tgt_pixel, ouv0, 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);
+ int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py;
- final_pixel[0] = (int)floorf(pixel[0]);
- final_pixel[1] = (int)floorf(pixel[1]);
+ int final_pixel[2] = { (int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h) };
/* 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;
+ {
+ if (bdata->best_index == NOT_FOUND)
+ bdata->best_index = OUT_OF_TEXTURE;
+
+ continue;
+ }
- final_index = final_pixel[0] + w * final_pixel[1];
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ int 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;
+ continue;
/* If final point is an "edge pixel", use it's "real" neighbor instead */
if (tempPoints[final_index].neighbour_pixel != -1) {
@@ -2513,11 +2546,125 @@ static int dynamic_paint_find_neighbour_pixel(
/* If we ended up to our origin point */
if (final_index == (px + w * py))
- return NOT_FOUND;
+ continue;
+ }
+
+ /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
+ if (tempPoints[final_index].tri_index != target_tri) {
+ /* Check if it's close enough to likely touch the intended triangle. Any triangle
+ * becomes thinner than a pixel at its vertices, so robustness requires some margin. */
+ const float final_pt[2] = { ((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h };
+ const float threshold = SQUARE(0.7f) / (w * h);
+
+ if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold)
+ continue;
+ }
+
+ bdata->best_index = final_index;
+ bdata->best_weight = dist_squared;
+ }
+}
+
+static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor)
+{
+ const int idx = ed->n_index[index];
+
+ for (int i = 0; i < ed->n_num[index]; i++) {
+ if (ed->n_target[idx + i] == neighbor) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Makes the adjacency data symmetric, except for border pixels. I.e. if A is neighbor of B, B is neighbor of A. */
+static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points)
+{
+ int *new_n_index = MEM_callocN(sizeof(int) * active_points, "Surface Adj Index");
+ int *new_n_num = MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts");
+
+ if (new_n_num && new_n_index) {
+ /* Count symmetrized neigbors */
+ int total_targets = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ total_targets += ed->n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ assert(!(ed->flags[target] & ADJ_BORDER_PIXEL));
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ new_n_num[target]++;
+ total_targets++;
+ }
+ }
}
- return final_index;
+ /* Allocate a new target map */
+ int *new_n_target = MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets");
+
+ if (new_n_target) {
+ /* Copy existing neighbors to the new map */
+ int n_pos = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ new_n_index[index] = n_pos;
+ memcpy(&new_n_target[n_pos], &ed->n_target[ed->n_index[index]], sizeof(int) * ed->n_num[index]);
+
+ /* Reset count to old, but advance position by new, leaving a gap to fill below. */
+ n_pos += new_n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ assert(n_pos == total_targets);
+
+ /* Add symmetrized - this loop behavior must exactly match the count pass above */
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ const int num = new_n_num[target]++;
+ new_n_target[new_n_index[target] + num] = index;
+ }
+ }
+ }
+
+ /* Swap maps */
+ MEM_freeN(ed->n_target);
+ ed->n_target = new_n_target;
+
+ MEM_freeN(ed->n_index);
+ ed->n_index = new_n_index;
+
+ MEM_freeN(ed->n_num);
+ ed->n_num = new_n_num;
+
+ ed->total_targets = total_targets;
+ return true;
+ }
}
+
+ if (new_n_index)
+ MEM_freeN(new_n_index);
+ if (new_n_num)
+ MEM_freeN(new_n_num);
+
+ return false;
}
int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
@@ -2668,30 +2815,28 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
&vert_to_looptri_map, &vert_to_looptri_map_mem,
dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm));
+ int total_border = 0;
+
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;
+ if (tempPoints[index].neighbour_pixel != -1) {
+ ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL;
+ total_border++;
+ }
+
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;
- }
- }
-
- if (!duplicate) {
+ if (!dynamicPaint_pointHasNeighbor(ed, final_index[index], final_index[n_target])) {
ed->n_target[n_pos] = final_index[n_target];
ed->n_num[final_index[index]]++;
n_pos++;
@@ -2707,6 +2852,57 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
MEM_freeN(vert_to_looptri_map);
MEM_freeN(vert_to_looptri_map_mem);
+
+ /* Make neighbors symmetric */
+ if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
+ error = true;
+ }
+
+ /* Create a list of border pixels */
+ ed->border = MEM_callocN(sizeof(int) * total_border, "Border Pixel Index");
+
+ if (ed->border) {
+ ed->total_border = total_border;
+
+ for (int i = 0, next = 0; i < active_points; i++) {
+ if (ed->flags[i] & ADJ_BORDER_PIXEL) {
+ ed->border[next++] = i;
+ }
+ }
+ }
+
+#if 0
+ /* -----------------------------------------------------------------
+ * For debug, write a dump of adjacency data to a file.
+ * -----------------------------------------------------------------*/
+ FILE *dump_file = fopen("dynpaint-adj-data.txt", "w");
+ int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp");
+ 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)
+ tmp[final_index[index]] = index;
+ }
+ }
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ const int fidx = final_index[index];
+
+ if (tempPoints[index].tri_index != -1) {
+ int nidx = tempPoints[index].neighbour_pixel;
+ fprintf(dump_file, "%d\t%d,%d\t%u\t%d,%d\t%d\t", fidx, tx, h-1-ty, tempPoints[index].tri_index, nidx<0?-1:(nidx%w), nidx<0?-1:h-1-(nidx/w), ed->flags[fidx]);
+ for (int i = 0; i < ed->n_num[fidx]; i++) {
+ int tgt = tmp[ed->n_target[ed->n_index[fidx]+i]];
+ fprintf(dump_file, "%s%d,%d", i?" ":"", tgt%w, h-1-tgt/w);
+ }
+ fprintf(dump_file, "\n");
+ }
+ }
+ }
+ MEM_freeN(tmp);
+ fclose(dump_file);
+#endif
}
}
@@ -4529,6 +4725,10 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
for (step = 0; step < steps; step++) {
for (index = 0; index < sData->total_points; index++) {
int i;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ continue;
+
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
float smudge_str = bData->brush_velocity[index * 4 + 3];
@@ -4708,6 +4908,9 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -4750,6 +4953,9 @@ static void dynamic_paint_effect_shrink_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -4796,6 +5002,10 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
const PaintPoint *prevPoint = data->prevPoint;
@@ -4964,6 +5174,80 @@ static void dynamicPaint_doEffectStep(
}
}
+static void dynamic_paint_border_cb(void *userdata, const int b_index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ const int index = sData->adj_data->border[b_index];
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Average neighboring points. Intermediaries use premultiplied alpha. */
+ float mix_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float mix_e_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float mix_wetness = 0.0f;
+
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const int target = n_target[n_idx];
+
+ PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target];
+
+ assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL));
+
+ madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]);
+ mix_color[3] += pPoint2->color[3];
+
+ madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]);
+ mix_e_color[3] += pPoint2->e_color[3];
+
+ mix_wetness += pPoint2->wetness;
+ }
+
+ const float divisor = 1.0f / numOfNeighs;
+
+ if (mix_color[3]) {
+ pPoint->color[3] = mix_color[3] * divisor;
+ mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]);
+ }
+ else {
+ pPoint->color[3] = 0.0f;
+ }
+
+ if (mix_e_color[3]) {
+ pPoint->e_color[3] = mix_e_color[3] * divisor;
+ mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]);
+ }
+ else {
+ pPoint->e_color[3] = 0.0f;
+ }
+
+ pPoint->wetness = mix_wetness / numOfNeighs;
+}
+
+static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface)
+{
+ PaintSurfaceData *sData = surface->data;
+
+ if (!sData->adj_data || !sData->adj_data->border)
+ return;
+
+ /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */
+ DynamicPaintEffectData data = {
+ .surface = surface
+ };
+
+ BLI_task_parallel_range(
+ 0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, sData->adj_data->total_border > 1000);
+}
+
static void dynamic_paint_wave_step_cb(void *userdata, const int index)
{
const DynamicPaintEffectData *data = userdata;
@@ -5636,6 +5920,11 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
if (force)
MEM_freeN(force);
}
+
+ /* paint island border pixels */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ dynamicPaint_doBorderStep(surface);
+ }
}
return ret;
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index a89d423e7a6..c67a61a5aad 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -47,6 +47,7 @@
#include "BLI_math.h"
#include "BLI_easing.h"
#include "BLI_threads.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 21fc1674dc5..0a0b023df82 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -40,6 +40,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
// function declarations
static FreestyleLineSet *alloc_lineset(void);
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index cd2eac078cf..30fc8915d46 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 730d5a93758..f3a85dcee2b 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -62,6 +62,7 @@
#include "BLI_blenlib.h"
#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 6cdeaf5e59b..8a7c1dd2833 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -38,6 +38,7 @@
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 64535f229a9..6b4b492b212 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -76,6 +76,8 @@
#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -272,8 +274,12 @@ void BKE_id_clear_newpoin(ID *id)
}
static int id_expand_local_callback(
- void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag))
+ void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int cb_flag)
{
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
/* Can hapen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)...
* Just skip it, shape key can only be either indirectly linked, or fully local, period.
* And let's curse one more time that stupid useless shapekey ID type! */
@@ -287,9 +293,9 @@ static int id_expand_local_callback(
/**
* 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)
+void BKE_id_expand_local(Main *bmain, ID *id)
{
- BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0);
+ BKE_library_foreach_ID_link(bmain, id, id_expand_local_callback, NULL, IDWALK_READONLY);
}
/**
@@ -298,7 +304,7 @@ void BKE_id_expand_local(ID *id)
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_expand_local(bmain, new_id);
BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
}
}
@@ -325,7 +331,7 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data_ex(bmain, id, id_in_mainlist);
- BKE_id_expand_local(id);
+ BKE_id_expand_local(bmain, id);
}
else {
ID *id_new;
@@ -1251,6 +1257,10 @@ void BKE_main_free(Main *mainvar)
}
}
+ if (mainvar->relations) {
+ BKE_main_relations_free(mainvar);
+ }
+
BLI_spin_end((SpinLock *)mainvar->lock);
MEM_freeN(mainvar->lock);
DEG_evaluation_context_free(mainvar->eval_ctx);
@@ -1267,6 +1277,78 @@ void BKE_main_unlock(struct Main *bmain)
BLI_spin_unlock((SpinLock *) bmain->lock);
}
+
+static int main_relations_create_cb(void *user_data, ID *id_self, ID **id_pointer, int cb_flag)
+{
+ MainIDRelations *rel = user_data;
+
+ if (*id_pointer) {
+ MainIDRelationsEntry *entry, **entry_p;
+
+ entry = BLI_mempool_alloc(rel->entry_pool);
+ if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) {
+ entry->next = *entry_p;
+ }
+ else {
+ entry->next = NULL;
+ }
+ entry->id_pointer = id_pointer;
+ entry->usage_flag = cb_flag;
+ *entry_p = entry;
+
+ entry = BLI_mempool_alloc(rel->entry_pool);
+ if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) {
+ entry->next = *entry_p;
+ }
+ else {
+ entry->next = NULL;
+ }
+ entry->id_pointer = (ID **)id_self;
+ entry->usage_flag = cb_flag;
+ *entry_p = entry;
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/** Generate the mappings between used IDs and their users, and vice-versa. */
+void BKE_main_relations_create(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a;
+
+ if (bmain->relations != NULL) {
+ BKE_main_relations_free(bmain);
+ }
+
+ bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
+ bmain->relations->id_used_to_user = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ bmain->relations->id_user_to_used = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ bmain->relations->entry_pool = BLI_mempool_create(sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);
+
+ for (a = set_listbasepointers(bmain, lbarray); a--; ) {
+ for (id = lbarray[a]->first; id; id = id->next) {
+ BKE_library_foreach_ID_link(NULL, id, main_relations_create_cb, bmain->relations, IDWALK_READONLY);
+ }
+ }
+}
+
+void BKE_main_relations_free(Main *bmain)
+{
+ if (bmain->relations) {
+ if (bmain->relations->id_used_to_user) {
+ BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL);
+ }
+ if (bmain->relations->id_user_to_used) {
+ BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL);
+ }
+ BLI_mempool_destroy(bmain->relations->entry_pool);
+ MEM_freeN(bmain->relations);
+ bmain->relations = NULL;
+ }
+}
+
/**
* Generates a raw .blend file thumbnail data from given image.
*
@@ -1407,7 +1489,8 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
static bool check_for_dupid(ListBase *lb, ID *id, char *name)
{
ID *idtest;
- int nr = 0, a, left_len;
+ int nr = 0, a;
+ size_t left_len;
#define MAX_IN_USE 64
bool in_use[MAX_IN_USE];
/* to speed up finding unused numbers within [1 .. MAX_IN_USE - 1] */
@@ -1441,7 +1524,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
/* Code above may have generated invalid utf-8 string, due to raw truncation.
* Ensure we get a valid one now! */
- left_len -= BLI_utf8_invalid_strip(left, left_len);
+ left_len -= (size_t)BLI_utf8_invalid_strip(left, left_len);
for (idtest = lb->first; idtest; idtest = idtest->next) {
int nrtest;
@@ -1483,7 +1566,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
* shave off the end chars until we have a unique name.
* Check the null terminators match as well so we don't get Cube.000 -> Cube.00 */
if (nr == 0 && name[left_len] == '\0') {
- int len;
+ size_t len;
/* FIXME: this code will never be executed, because either nr will be
* at least 1, or name will not end at left_len! */
BLI_assert(0);
@@ -1621,6 +1704,53 @@ void BKE_main_id_clear_newpoins(Main *bmain)
}
}
+
+static void library_make_local_copying_check(ID *id, GSet *loop_tags, MainIDRelations *id_relations, GSet *done_ids)
+{
+ if (BLI_gset_haskey(done_ids, id)) {
+ return; /* Already checked, nothing else to do. */
+ }
+
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id);
+ BLI_gset_insert(loop_tags, id);
+ for (; entry != NULL; entry = entry->next) {
+ ID *par_id = (ID *)entry->id_pointer; /* used_to_user stores ID pointer, not pointer to ID pointer... */
+
+ /* Shapekeys are considered 'private' to their owner ID here, and never tagged (since they cannot be linked),
+ * so we have to switch effective parent to their owner. */
+ if (GS(par_id->name) == ID_KE) {
+ par_id = ((Key *)par_id)->from;
+ }
+
+ if (par_id->lib == NULL) {
+ /* Local user, early out to avoid some gset querying... */
+ continue;
+ }
+ if (!BLI_gset_haskey(done_ids, par_id)) {
+ if (BLI_gset_haskey(loop_tags, par_id)) {
+ /* We are in a 'dependency loop' of IDs, this does not say us anything, skip it.
+ * Note that this is the situation that can lead to archipelagoes of linked data-blocks
+ * (since all of them have non-local users, they would all be duplicated, leading to a loop of unused
+ * linked data-blocks that cannot be freed since they all use each other...). */
+ continue;
+ }
+ /* Else, recursively check that user ID. */
+ library_make_local_copying_check(par_id, loop_tags, id_relations, done_ids);
+ }
+
+ if (par_id->tag & LIB_TAG_DOIT) {
+ /* This user will be fully local in future, so far so good, nothing to do here but check next user. */
+ }
+ else {
+ /* This user won't be fully local in future, so current ID won't be either. And we are done checking it. */
+ id->tag &= ~LIB_TAG_DOIT;
+ break;
+ }
+ }
+ BLI_gset_add(done_ids, id);
+ BLI_gset_remove(loop_tags, id, NULL);
+}
+
/** Make linked datablocks local.
*
* \param bmain Almost certainly G.main.
@@ -1631,11 +1761,10 @@ void BKE_main_id_clear_newpoins(Main *bmain)
/* Note: 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, which 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).
- *
- * However, we now have a first check that allows us to use 'direct localization' of a lot of IDs, so performances
- * are now *reasonably* OK.
+ * Current version uses regular id_make_local callback, with advanced pre-processing step to detect all cases of
+ * IDs currently indirectly used, but which will be used by local data only once this function is finished.
+ * This allows to avoid any uneeded duplication of IDs, and hence all time lost afterwards to remove
+ * orphaned linked data-blocks...
*/
void BKE_library_make_local(
Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake)
@@ -1646,9 +1775,12 @@ void BKE_library_make_local(
LinkNode *todo_ids = NULL;
LinkNode *copied_ids = NULL;
- LinkNode *linked_loop_candidates = NULL;
MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__);
+ BKE_main_relations_create(bmain);
+
+ GSet *done_ids = BLI_gset_ptr_new(__func__);
+
/* Step 1: Detect datablocks to make local. */
for (a = set_listbasepointers(bmain, lbarray); a--; ) {
id = lbarray[a]->first;
@@ -1658,16 +1790,25 @@ void BKE_library_make_local(
const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
for (; id; id = id->next) {
+ ID *ntree = (ID *)ntreeFromID(id);
+
id->tag &= ~LIB_TAG_DOIT;
+ if (ntree != NULL) {
+ ntree->tag &= ~LIB_TAG_DOIT;
+ }
if (id->lib == NULL) {
id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
}
- /* The check on the fourth 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).
+ /* The check on the fourth 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).
* Also, never ever make proxified objects local, would not make any sense. */
+ /* Some more notes:
+ * - Shapekeys are never tagged here (since they are not linkable).
+ * - Nodetrees used in materials etc. have to be tagged manually, since they do not exist in Main (!).
+ * This is ok-ish on 'make local' side of things (since those are handled by their 'owner' IDs),
+ * but complicates slightly the pre-processing of relations between IDs at step 2... */
else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
ELEM(lib, NULL, id->lib) &&
!(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) &&
@@ -1675,13 +1816,32 @@ void BKE_library_make_local(
{
BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem);
id->tag |= LIB_TAG_DOIT;
+
+ /* Tag those nasty non-ID nodetrees, but do not add them to todo list, making them local is handled
+ * by 'owner' ID. This is needed for library_make_local_copying_check() to work OK at step 2. */
+ if (ntree != NULL) {
+ ntree->tag |= LIB_TAG_DOIT;
+ }
+ }
+ else {
+ /* Linked ID that we won't be making local (needed info for step 2, see below). */
+ BLI_gset_add(done_ids, id);
}
}
}
/* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future,
- * local data), others will need to be duplicated and further processed later. */
- BKE_library_indirectly_used_data_tag_clear(bmain);
+ * local data), others will need to be duplicated. */
+ GSet *loop_tags = BLI_gset_ptr_new(__func__);
+ for (LinkNode *it = todo_ids; it; it = it->next) {
+ library_make_local_copying_check(it->link, loop_tags, bmain->relations, done_ids);
+ BLI_assert(BLI_gset_size(loop_tags) == 0);
+ }
+ BLI_gset_free(loop_tags, NULL);
+ BLI_gset_free(done_ids, NULL);
+
+ /* Next step will most likely add new IDs, better to get rid of this mapping now. */
+ BKE_main_relations_free(bmain);
/* Step 3: Make IDs local, either directly (quick and simple), or using generic process,
* which involves more complex checks and might instead create a local copy of original linked ID. */
@@ -1691,10 +1851,10 @@ void BKE_library_make_local(
if (id->tag & LIB_TAG_DOIT) {
/* We know all users of this object are local or will be made fully local, even if currently there are
- * some indirect usages. So instead of making a copy that se'll likely get rid of later, directly make
+ * some indirect usages. So instead of making a copy that we'll likely get rid of later, directly make
* that data block local. Saves a tremendous amount of time with complex scenes... */
id_clear_lib_data_ex(bmain, id, true);
- BKE_id_expand_local(id);
+ BKE_id_expand_local(bmain, id);
id->tag &= ~LIB_TAG_DOIT;
}
else {
@@ -1730,6 +1890,9 @@ void BKE_library_make_local(
/* Step 4: We have to remap local usages of old (linked) ID to new (local) id in a separated 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. */
+ /* TODO This is now the biggest step by far (in term of processing time). We may be able to gain here by
+ * using again main->relations mapping, but... this implies BKE_libblock_remap & co to be able to update
+ * main->relations on the fly. Have to think about it a bit more, and see whether new code is OK first, anyway. */
for (LinkNode *it = copied_ids; it; it = it->next) {
id = it->link;
@@ -1748,6 +1911,53 @@ void BKE_library_make_local(
}
}
+ /* Note: Keeping both version of the code (old one being safer, since it still has checks against unused IDs)
+ * for now, we can remove old one once it has been tested for some time in master... */
+#if 1
+ /* Step 5: proxy 'remapping' hack. */
+ for (LinkNode *it = copied_ids; it; it = it->next) {
+ /* 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;
+ bool is_local = false, is_lib = false;
+
+ /* 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);
+ continue;
+ }
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ /* 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! */
+ 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;
+ }
+ }
+ }
+#else
+ LinkNode *linked_loop_candidates = NULL;
+
/* Step 5: 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;
@@ -1798,6 +2008,8 @@ void BKE_library_make_local(
if (!is_local) {
if (!is_lib) { /* Not used at all, we can free it! */
+ BLI_assert(!"Unused linked data copy remaining from MakeLibLocal process, should not happen anymore");
+ printf("\t%s (from %s)\n", id->name, id->lib->id.name);
BKE_libblock_free(bmain, id);
it->link = NULL;
do_loop = true;
@@ -1811,7 +2023,7 @@ void BKE_library_make_local(
/* 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 they used as 'directly used' in sixth step. */
ID *ntree = (ID *)ntreeFromID(id);
if (ntree != NULL) {
ntree->tag |= LIB_TAG_DOIT;
@@ -1836,6 +2048,7 @@ void BKE_library_make_local(
/* 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) {
+ BLI_assert(!"Unused linked data copy remaining from MakeLibLocal process (archipelago case), should not happen anymore");
/* Object's deletion rely on valid ob->data, but ob->data may have already been freed here...
* Setting it to NULL may not be 100% correct, but should be safe and do the work. */
if (GS(id->name) == ID_OB) {
@@ -1856,6 +2069,7 @@ void BKE_library_make_local(
it->link = NULL;
}
}
+#endif
BKE_main_id_clear_newpoins(bmain);
BLI_memarena_free(linklist_mem);
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index fa75c906fb1..9685f1f5af6 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -84,11 +84,12 @@
#define FOREACH_FINALIZE _finalize
#define FOREACH_FINALIZE_VOID FOREACH_FINALIZE: (void)0
-#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, cb_flag) \
+#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \
+ CHECK_TYPE(id_pp, ID **); \
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 | (_data)->cd_flag); \
+ const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, _cb_flag | (_data)->cb_flag); \
if (_flag & IDWALK_READONLY) { \
BLI_assert(*(id_pp) == old_id); \
} \
@@ -129,7 +130,7 @@ enum {
typedef struct LibraryForeachIDData {
ID *self_id;
int flag;
- int cd_flag;
+ int cb_flag;
LibraryIDLinkCallback callback;
void *user_data;
int status;
@@ -140,19 +141,19 @@ typedef struct LibraryForeachIDData {
} LibraryForeachIDData;
static void library_foreach_rigidbodyworldSceneLooper(
- struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cd_flag)
+ struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_modifiersForeachIDLink(
- void *user_data, Object *UNUSED(object), ID **id_pointer, int cd_flag)
+ void *user_data, Object *UNUSED(object), ID **id_pointer, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
@@ -161,44 +162,44 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID
bool is_reference, void *user_data)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- const int cd_flag = is_reference ? IDWALK_USER : IDWALK_NOP;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_particlesystemsObjectLooper(
- ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cd_flag)
+ ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_sensorsObjectLooper(
- bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cd_flag)
+ bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_controllersObjectLooper(
- bController *UNUSED(controller), ID **id_pointer, void *user_data, int cd_flag)
+ bController *UNUSED(controller), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_actuatorsObjectLooper(
- bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cd_flag)
+ bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
@@ -207,7 +208,7 @@ static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *stri
{
NlaStrip *substrip;
- FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER);
for (substrip = strip->strips.first; substrip; substrip = substrip->next) {
library_foreach_nla_strip(data, substrip);
@@ -230,14 +231,14 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
/* only used targets */
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP);
}
DRIVER_TARGETS_LOOPER_END
}
}
- FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_USER);
- FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER);
+ FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_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) {
@@ -250,23 +251,28 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
{
- FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_NOP);
- FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_CB_NOP);
+ FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_CB_USER);
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_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER);
+ FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_ID_as_subdata_link(
- ID *id, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
+ ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
{
+ /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */
+ ID *id = *id_pp;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_PRIVATE);
+ BLI_assert(id == *id_pp);
+
if (flag & IDWALK_RECURSE) {
/* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in IDWALK_RECURSE case is
* troublesome, see T49553. */
@@ -276,8 +282,10 @@ static void library_foreach_ID_as_subdata_link(
}
}
else {
- BKE_library_foreach_ID_link(id, callback, user_data, flag);
+ BKE_library_foreach_ID_link(NULL, id, callback, user_data, flag);
}
+
+ FOREACH_FINALIZE_VOID;
}
/**
@@ -285,7 +293,7 @@ static void library_foreach_ID_as_subdata_link(
*
* \note: May be extended to be recursive in the future.
*/
-void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
+void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
{
LibraryForeachIDData data;
int i;
@@ -313,9 +321,21 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag)
- do {
+ for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
data.self_id = id;
- data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0;
+ data.cb_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_CB_INDIRECT_USAGE : 0;
+
+ if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY)) {
+ /* Note that this is minor optimization, even in worst cases (like id being an object with lots of
+ * drivers and constraints and modifiers, or material etc. with huge node tree),
+ * but we might as well use it (Main->relations is always assumed valid, it's responsability of code
+ * creating it to free it, especially if/when it starts modifying Main database). */
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
+ for (; entry != NULL; entry = entry->next) {
+ FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag);
+ }
+ continue;
+ }
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
@@ -326,7 +346,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_LI:
{
Library *lib = (Library *) id;
- CALLBACK_INVOKE(lib->parent, IDWALK_NOP);
+ CALLBACK_INVOKE(lib->parent, IDWALK_CB_NOP);
break;
}
case ID_SCE:
@@ -336,39 +356,39 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
SceneRenderLayer *srl;
Base *base;
- CALLBACK_INVOKE(scene->camera, IDWALK_NOP);
- CALLBACK_INVOKE(scene->world, IDWALK_USER);
- CALLBACK_INVOKE(scene->set, IDWALK_NOP);
- CALLBACK_INVOKE(scene->clip, IDWALK_USER);
+ CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(scene->world, IDWALK_CB_USER);
+ CALLBACK_INVOKE(scene->set, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(scene->clip, IDWALK_CB_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);
+ 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);
+ CALLBACK_INVOKE(scene->obedit, IDWALK_CB_NOP);
for (srl = scene->r.layers.first; srl; srl = srl->next) {
FreestyleModuleConfig *fmc;
FreestyleLineSet *fls;
if (srl->mat_override) {
- CALLBACK_INVOKE(srl->mat_override, IDWALK_USER);
+ CALLBACK_INVOKE(srl->mat_override, IDWALK_CB_USER);
}
if (srl->light_override) {
- CALLBACK_INVOKE(srl->light_override, IDWALK_USER);
+ CALLBACK_INVOKE(srl->light_override, IDWALK_CB_USER);
}
for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
if (fmc->script) {
- CALLBACK_INVOKE(fmc->script, IDWALK_NOP);
+ CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
}
}
for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
if (fls->group) {
- CALLBACK_INVOKE(fls->group, IDWALK_USER);
+ CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
}
if (fls->linestyle) {
- CALLBACK_INVOKE(fls->linestyle, IDWALK_USER);
+ CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
}
}
}
@@ -377,39 +397,39 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Sequence *seq;
SEQP_BEGIN(scene->ed, seq)
{
- CALLBACK_INVOKE(seq->scene, IDWALK_NOP);
- CALLBACK_INVOKE(seq->scene_camera, IDWALK_NOP);
- CALLBACK_INVOKE(seq->clip, IDWALK_USER);
- CALLBACK_INVOKE(seq->mask, IDWALK_USER);
- CALLBACK_INVOKE(seq->sound, IDWALK_USER);
+ CALLBACK_INVOKE(seq->scene, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(seq->scene_camera, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER);
+ CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER);
+ CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER);
for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) {
- CALLBACK_INVOKE(smd->mask_id, IDWALK_USER);
+ CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER);
}
}
SEQ_END
}
- CALLBACK_INVOKE(scene->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
for (base = scene->base.first; base; base = base->next) {
- CALLBACK_INVOKE(base->object, IDWALK_USER);
+ CALLBACK_INVOKE(base->object, IDWALK_CB_USER);
}
for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
- CALLBACK_INVOKE(marker->camera, IDWALK_NOP);
+ CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
}
if (toolsett) {
- CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_CB_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->particle.scene, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_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);
+ CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_CB_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_CB_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_CB_USER);
if (toolsett->vpaint) {
library_foreach_paint(&data, &toolsett->vpaint->paint);
@@ -419,7 +439,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (toolsett->sculpt) {
library_foreach_paint(&data, &toolsett->sculpt->paint);
- CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_CB_NOP);
}
if (toolsett->uvsculpt) {
library_foreach_paint(&data, &toolsett->uvsculpt->paint);
@@ -430,7 +450,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
}
- CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_NOP);
+ CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_CB_NOP);
break;
}
@@ -441,75 +461,75 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
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;
+ const int data_cb_flag = data.cb_flag;
+ const int proxy_cb_flag = (object->proxy || object->proxy_group) ? IDWALK_CB_INDIRECT_USAGE : 0;
/* object data special case */
- data.cd_flag |= proxy_cd_flag;
+ data.cb_flag |= proxy_cb_flag;
if (object->type == OB_EMPTY) {
/* empty can have NULL or Image */
- CALLBACK_INVOKE_ID(object->data, IDWALK_USER);
+ CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER);
}
else {
/* when set, this can't be NULL */
if (object->data) {
- CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL);
+ CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
}
}
- data.cd_flag = data_cd_flag;
+ data.cb_flag = data_cb_flag;
- CALLBACK_INVOKE(object->parent, IDWALK_NOP);
- CALLBACK_INVOKE(object->track, IDWALK_NOP);
+ CALLBACK_INVOKE(object->parent, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(object->track, IDWALK_CB_NOP);
/* object->proxy is refcounted, but not object->proxy_group... *sigh* */
- CALLBACK_INVOKE(object->proxy, IDWALK_USER);
- CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
+ CALLBACK_INVOKE(object->proxy, IDWALK_CB_USER);
+ CALLBACK_INVOKE(object->proxy_group, IDWALK_CB_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;
+ data.cb_flag = ID_IS_LINKED_DATABLOCK(object->proxy_from) ? IDWALK_CB_INDIRECT_USAGE : 0;
}
- CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
- data.cd_flag = data_cd_flag;
+ CALLBACK_INVOKE(object->proxy_from, IDWALK_CB_NOP);
+ data.cb_flag = data_cb_flag;
- CALLBACK_INVOKE(object->poselib, IDWALK_USER);
+ CALLBACK_INVOKE(object->poselib, IDWALK_CB_USER);
- data.cd_flag |= proxy_cd_flag;
+ data.cb_flag |= proxy_cb_flag;
for (i = 0; i < object->totcol; i++) {
- CALLBACK_INVOKE(object->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(object->mat[i], IDWALK_CB_USER);
}
- data.cd_flag = data_cd_flag;
+ data.cb_flag = data_cb_flag;
- CALLBACK_INVOKE(object->gpd, IDWALK_USER);
- CALLBACK_INVOKE(object->dup_group, IDWALK_USER);
+ CALLBACK_INVOKE(object->gpd, IDWALK_CB_USER);
+ CALLBACK_INVOKE(object->dup_group, IDWALK_CB_USER);
if (object->pd) {
- CALLBACK_INVOKE(object->pd->tex, IDWALK_USER);
- CALLBACK_INVOKE(object->pd->f_source, IDWALK_NOP);
+ CALLBACK_INVOKE(object->pd->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(object->pd->f_source, IDWALK_CB_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;
+ data.cb_flag |= proxy_cb_flag;
for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
- CALLBACK_INVOKE(pchan->custom, IDWALK_USER);
+ CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER);
BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data);
}
- data.cd_flag = data_cd_flag;
+ data.cb_flag = data_cb_flag;
}
if (object->rigidbody_constraint) {
- CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_NOP);
- CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_NOP);
+ CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_CB_NOP);
}
if (object->lodlevels.first) {
LodLevel *level;
for (level = object->lodlevels.first; level; level = level->next) {
- CALLBACK_INVOKE(level->source, IDWALK_NOP);
+ CALLBACK_INVOKE(level->source, IDWALK_CB_NOP);
}
}
@@ -521,10 +541,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (object->soft) {
- CALLBACK_INVOKE(object->soft->collision_group, IDWALK_NOP);
+ CALLBACK_INVOKE(object->soft->collision_group, IDWALK_CB_NOP);
if (object->soft->effector_weights) {
- CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP);
+ CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP);
}
}
@@ -537,10 +557,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_ME:
{
Mesh *mesh = (Mesh *) id;
- CALLBACK_INVOKE(mesh->texcomesh, IDWALK_USER);
- CALLBACK_INVOKE(mesh->key, IDWALK_USER);
+ CALLBACK_INVOKE(mesh->texcomesh, IDWALK_CB_USER);
+ CALLBACK_INVOKE(mesh->key, IDWALK_CB_USER);
for (i = 0; i < mesh->totcol; i++) {
- CALLBACK_INVOKE(mesh->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER);
}
/* XXX Really not happy with this - probably texface should rather use some kind of
@@ -552,7 +572,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data;
for (int j = 0; j < mesh->totpoly; j++, txface++) {
- CALLBACK_INVOKE(txface->tpage, IDWALK_USER_ONE);
+ CALLBACK_INVOKE(txface->tpage, IDWALK_CB_USER_ONE);
}
}
}
@@ -562,7 +582,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
MTFace *tface = (MTFace *)mesh->fdata.layers[i].data;
for (int j = 0; j < mesh->totface; j++, tface++) {
- CALLBACK_INVOKE(tface->tpage, IDWALK_USER_ONE);
+ CALLBACK_INVOKE(tface->tpage, IDWALK_CB_USER_ONE);
}
}
}
@@ -573,17 +593,17 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_CU:
{
Curve *curve = (Curve *) id;
- CALLBACK_INVOKE(curve->bevobj, IDWALK_NOP);
- CALLBACK_INVOKE(curve->taperobj, IDWALK_NOP);
- CALLBACK_INVOKE(curve->textoncurve, IDWALK_NOP);
- CALLBACK_INVOKE(curve->key, IDWALK_USER);
+ CALLBACK_INVOKE(curve->bevobj, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->taperobj, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->textoncurve, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->key, IDWALK_CB_USER);
for (i = 0; i < curve->totcol; i++) {
- CALLBACK_INVOKE(curve->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(curve->mat[i], IDWALK_CB_USER);
}
- CALLBACK_INVOKE(curve->vfont, IDWALK_USER);
- CALLBACK_INVOKE(curve->vfontb, IDWALK_USER);
- CALLBACK_INVOKE(curve->vfonti, IDWALK_USER);
- CALLBACK_INVOKE(curve->vfontbi, IDWALK_USER);
+ CALLBACK_INVOKE(curve->vfont, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfontb, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfonti, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfontbi, IDWALK_CB_USER);
break;
}
@@ -591,7 +611,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
{
MetaBall *metaball = (MetaBall *) id;
for (i = 0; i < metaball->totcol; i++) {
- CALLBACK_INVOKE(metaball->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(metaball->mat[i], IDWALK_CB_USER);
}
break;
}
@@ -606,9 +626,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
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);
+ library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data);
}
- CALLBACK_INVOKE(material->group, IDWALK_USER);
+ CALLBACK_INVOKE(material->group, IDWALK_CB_USER);
break;
}
@@ -617,26 +637,26 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Tex *texture = (Tex *) id;
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);
+ library_foreach_ID_as_subdata_link((ID **)&texture->nodetree, callback, user_data, flag, &data);
}
- CALLBACK_INVOKE(texture->ima, IDWALK_USER);
+ CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
if (texture->env) {
- CALLBACK_INVOKE(texture->env->object, IDWALK_NOP);
- CALLBACK_INVOKE(texture->env->ima, IDWALK_USER);
+ CALLBACK_INVOKE(texture->env->object, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(texture->env->ima, IDWALK_CB_USER);
}
if (texture->pd)
- CALLBACK_INVOKE(texture->pd->object, IDWALK_NOP);
+ CALLBACK_INVOKE(texture->pd->object, IDWALK_CB_NOP);
if (texture->vd)
- CALLBACK_INVOKE(texture->vd->object, IDWALK_NOP);
+ CALLBACK_INVOKE(texture->vd->object, IDWALK_CB_NOP);
if (texture->ot)
- CALLBACK_INVOKE(texture->ot->object, IDWALK_NOP);
+ CALLBACK_INVOKE(texture->ot->object, IDWALK_CB_NOP);
break;
}
case ID_LT:
{
Lattice *lattice = (Lattice *) id;
- CALLBACK_INVOKE(lattice->key, IDWALK_USER);
+ CALLBACK_INVOKE(lattice->key, IDWALK_CB_USER);
break;
}
@@ -650,7 +670,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
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);
+ library_foreach_ID_as_subdata_link((ID **)&lamp->nodetree, callback, user_data, flag, &data);
}
break;
}
@@ -658,7 +678,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_CA:
{
Camera *camera = (Camera *) id;
- CALLBACK_INVOKE(camera->dof_ob, IDWALK_NOP);
+ CALLBACK_INVOKE(camera->dof_ob, IDWALK_CB_NOP);
break;
}
@@ -669,14 +689,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
* (see also foreach_libblock_id_users_callback).
*/
Key *key = (Key *) id;
- CALLBACK_INVOKE_ID(key->from, IDWALK_NOP);
+ CALLBACK_INVOKE_ID(key->from, IDWALK_CB_NOP);
break;
}
case ID_SCR:
{
bScreen *screen = (bScreen *) id;
- CALLBACK_INVOKE(screen->scene, IDWALK_USER_ONE);
+ CALLBACK_INVOKE(screen->scene, IDWALK_CB_USER_ONE);
break;
}
@@ -690,7 +710,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
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);
+ library_foreach_ID_as_subdata_link((ID **)&world->nodetree, callback, user_data, flag, &data);
}
break;
}
@@ -698,7 +718,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_SPK:
{
Speaker *speaker = (Speaker *) id;
- CALLBACK_INVOKE(speaker->sound, IDWALK_USER);
+ CALLBACK_INVOKE(speaker->sound, IDWALK_CB_USER);
break;
}
@@ -707,7 +727,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Group *group = (Group *) id;
GroupObject *gob;
for (gob = group->gobject.first; gob; gob = gob->next) {
- CALLBACK_INVOKE(gob->ob, IDWALK_USER_ONE);
+ CALLBACK_INVOKE(gob->ob, IDWALK_CB_USER_ONE);
}
break;
}
@@ -716,9 +736,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
{
bNodeTree *ntree = (bNodeTree *) id;
bNode *node;
- CALLBACK_INVOKE(ntree->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER);
for (node = ntree->nodes.first; node; node = node->next) {
- CALLBACK_INVOKE_ID(node->id, IDWALK_USER);
+ CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER);
}
break;
}
@@ -726,9 +746,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_BR:
{
Brush *brush = (Brush *) id;
- CALLBACK_INVOKE(brush->toggle_brush, IDWALK_NOP);
- CALLBACK_INVOKE(brush->clone.image, IDWALK_NOP);
- CALLBACK_INVOKE(brush->paint_curve, IDWALK_USER);
+ CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
library_foreach_mtex(&data, &brush->mtex);
library_foreach_mtex(&data, &brush->mask_mtex);
break;
@@ -737,10 +757,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_PA:
{
ParticleSettings *psett = (ParticleSettings *) id;
- CALLBACK_INVOKE(psett->dup_group, IDWALK_NOP);
- CALLBACK_INVOKE(psett->dup_ob, IDWALK_NOP);
- CALLBACK_INVOKE(psett->bb_ob, IDWALK_NOP);
- CALLBACK_INVOKE(psett->collision_group, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->dup_group, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->dup_ob, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->bb_ob, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->collision_group, IDWALK_CB_NOP);
for (i = 0; i < MAX_MTEX; i++) {
if (psett->mtex[i]) {
@@ -749,16 +769,16 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (psett->effector_weights) {
- CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_CB_NOP);
}
if (psett->pd) {
- CALLBACK_INVOKE(psett->pd->tex, IDWALK_USER);
- CALLBACK_INVOKE(psett->pd->f_source, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->pd->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(psett->pd->f_source, IDWALK_CB_NOP);
}
if (psett->pd2) {
- CALLBACK_INVOKE(psett->pd2->tex, IDWALK_USER);
- CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->pd2->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_CB_NOP);
}
if (psett->boids) {
@@ -769,11 +789,11 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
for (rule = state->rules.first; rule; rule = rule->next) {
if (rule->type == eBoidRuleType_Avoid) {
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- CALLBACK_INVOKE(gabr->ob, IDWALK_NOP);
+ CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP);
}
else if (rule->type == eBoidRuleType_FollowLeader) {
BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- CALLBACK_INVOKE(flbr->ob, IDWALK_NOP);
+ CALLBACK_INVOKE(flbr->ob, IDWALK_CB_NOP);
}
}
}
@@ -789,19 +809,19 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
MovieTrackingTrack *track;
MovieTrackingPlaneTrack *plane_track;
- CALLBACK_INVOKE(clip->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(clip->gpd, IDWALK_CB_USER);
for (track = tracking->tracks.first; track; track = track->next) {
- CALLBACK_INVOKE(track->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(track->gpd, IDWALK_CB_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);
+ CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
}
}
for (plane_track = tracking->plane_tracks.first; plane_track; plane_track = plane_track->next) {
- CALLBACK_INVOKE(plane_track->image, IDWALK_USER);
+ CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER);
}
break;
}
@@ -816,7 +836,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
for (mask_spline = mask_layer->splines.first; mask_spline; mask_spline = mask_spline->next) {
for (i = 0; i < mask_spline->tot_point; i++) {
MaskSplinePoint *point = &mask_spline->points[i];
- CALLBACK_INVOKE_ID(point->parent.id, IDWALK_USER);
+ CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER);
}
}
}
@@ -834,14 +854,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
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);
+ 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) {
LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)lsm;
if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
}
}
}
@@ -849,7 +869,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)lsm;
if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
}
}
}
@@ -857,7 +877,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)lsm;
if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
}
}
}
@@ -868,7 +888,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
bAction *act = (bAction *) id;
for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
- CALLBACK_INVOKE(marker->camera, IDWALK_NOP);
+ CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
}
break;
}
@@ -891,7 +911,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
break;
}
- } while ((id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL));
+ }
FOREACH_FINALIZE:
if (data.ids_handled) {
@@ -909,13 +929,13 @@ FOREACH_FINALIZE:
/**
* re-usable function, use when replacing ID's
*/
-void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag)
+void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
{
- if (cd_flag & IDWALK_USER) {
+ if (cb_flag & IDWALK_CB_USER) {
id_us_min(id_src);
id_us_plus(id_dst);
}
- else if (cd_flag & IDWALK_USER_ONE) {
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
id_us_ensure_real(id_dst);
}
}
@@ -1049,7 +1069,7 @@ static int foreach_libblock_id_users_callback(void *user_data, ID *self_id, ID *
(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) {
+ if (cb_flag & IDWALK_CB_INDIRECT_USAGE) {
iter->count_indirect++;
}
else {
@@ -1080,7 +1100,7 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
iter.curr_id = id_user;
iter.count_direct = iter.count_indirect = 0;
- BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP);
+ BKE_library_foreach_ID_link(NULL, iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_READONLY);
return iter.count_direct + iter.count_indirect;
}
@@ -1109,7 +1129,7 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
}
iter.curr_id = id_curr;
BKE_library_foreach_ID_link(
- id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+ bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
}
@@ -1160,7 +1180,7 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
continue;
}
iter.curr_id = id_curr;
- BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+ BKE_library_foreach_ID_link(bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
}
@@ -1237,7 +1257,8 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
/* Unused ID (so far), no need to check it further. */
continue;
}
- BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
}
}
}
@@ -1264,7 +1285,8 @@ void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
/* Local or non-indirectly-used ID (so far), no need to check it further. */
continue;
}
- BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
}
}
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index d7d566a9ec0..a408b498f18 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -158,6 +158,10 @@ enum {
static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id_p, int cb_flag)
{
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
IDRemap *id_remap_data = user_data;
ID *old_id = id_remap_data->old_id;
ID *new_id = id_remap_data->new_id;
@@ -169,14 +173,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
if (*id_p && (*id_p == old_id)) {
- const bool is_indirect = (cb_flag & IDWALK_INDIRECT_USAGE) != 0;
+ const bool is_indirect = (cb_flag & IDWALK_CB_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) &&
+ const bool is_never_null = ((cb_flag & IDWALK_CB_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;
@@ -185,7 +189,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
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)) {
+ if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) {
id->tag |= LIB_TAG_DOIT;
}
@@ -203,10 +207,10 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
else {
BLI_assert(0);
}
- if (cb_flag & IDWALK_USER) {
+ if (cb_flag & IDWALK_CB_USER) {
id_remap_data->skipped_refcounted++;
}
- else if (cb_flag & IDWALK_USER_ONE) {
+ else if (cb_flag & IDWALK_CB_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;
}
@@ -216,13 +220,13 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
*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) {
+ if (cb_flag & IDWALK_CB_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) {
+ else if (cb_flag & IDWALK_CB_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... */
@@ -434,7 +438,7 @@ ATTR_NONNULL(1) static void libblock_remap_data(
#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);
+ BKE_library_foreach_ID_link(NULL, id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
}
else {
i = set_listbasepointers(bmain, lb_array);
@@ -456,7 +460,7 @@ ATTR_NONNULL(1) static void libblock_remap_data(
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);
+ NULL, id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
}
}
}
@@ -685,13 +689,17 @@ void BKE_libblock_relink_ex(
}
}
-static int id_relink_to_newid_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
+static int id_relink_to_newid_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cb_flag)
{
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
ID *id = *id_pointer;
if (id) {
/* See: NEW_ID macro */
if (id->newid) {
- BKE_library_update_ID_link_user(id->newid, id, cd_flag);
+ BKE_library_update_ID_link_user(id->newid, id, cb_flag);
*id_pointer = id->newid;
}
else if (id->tag & LIB_TAG_NEW) {
@@ -711,7 +719,7 @@ void BKE_libblock_relink_to_newid(ID *id)
if (ID_IS_LINKED_DATABLOCK(id))
return;
- BKE_library_foreach_ID_link(id, id_relink_to_newid_looper, NULL, 0);
+ BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0);
}
void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id)
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index bd21215f91e..1eb909bd9f9 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -41,6 +41,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 21023d9f53c..6f23b82c6df 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -36,8 +36,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 8d024ea9aa5..97033a9555d 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -49,6 +49,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 2068854421f..5c0b09f0ff0 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -41,8 +41,8 @@
#include "DNA_scene_types.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_memarena.h"
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 41e4c21d814..2276d56b9c6 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -49,10 +49,11 @@
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
+#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index c321bc92a71..148fc3827e0 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -40,9 +40,9 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_ghash.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index f16e8f328d4..3f3b4896653 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -46,10 +46,11 @@
#include "DNA_world_types.h"
#include "DNA_linestyle_types.h"
-#include "BLI_string.h"
-#include "BLI_math.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index e93bfcdda83..ff8be5892e9 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1204,7 +1204,7 @@ void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, con
if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data(bmain, &ob->id);
- BKE_id_expand_local(&ob->id);
+ BKE_id_expand_local(bmain, &ob->id);
if (clear_proxy) {
if (ob->proxy_from != NULL) {
ob->proxy_from->proxy = NULL;
@@ -2236,18 +2236,6 @@ void BKE_boundbox_minmax(const BoundBox *bb, float obmat[4][4], float r_min[3],
}
}
-void BKE_boundbox_scale(struct BoundBox *bb_dst, const struct BoundBox *bb_src, float scale)
-{
- float cent[3];
- BKE_boundbox_calc_center_aabb(bb_src, cent);
-
- for (int i = 0; i < ARRAY_SIZE(bb_dst->vec); i++) {
- bb_dst->vec[i][0] = ((bb_src->vec[i][0] - cent[0]) * scale) + cent[0];
- bb_dst->vec[i][1] = ((bb_src->vec[i][1] - cent[1]) * scale) + cent[1];
- bb_dst->vec[i][2] = ((bb_src->vec[i][2] - cent[2]) * scale) + cent[2];
- }
-}
-
/**
* Returns a BBox which each dimensions are at least epsilon.
* \note In case a given dimension needs to be enlarged, its final value will be in [epsilon, 3 * epsilon] range.
@@ -2816,45 +2804,6 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
return 1;
}
-/*
- * Test a bounding box for ray intersection
- * assumes the ray is already local to the boundbox space
- */
-bool BKE_boundbox_ray_hit_check(
- const struct BoundBox *bb,
- const float ray_start[3], const float ray_normal[3],
- float *r_lambda)
-{
- const int triangle_indexes[12][3] = {
- {0, 1, 2}, {0, 2, 3},
- {3, 2, 6}, {3, 6, 7},
- {1, 2, 6}, {1, 6, 5},
- {5, 6, 7}, {4, 5, 7},
- {0, 3, 7}, {0, 4, 7},
- {0, 1, 5}, {0, 4, 5}};
-
- bool result = false;
- int i;
-
- for (i = 0; i < 12 && (!result || r_lambda); i++) {
- float lambda;
- int v1, v2, v3;
- v1 = triangle_indexes[i][0];
- v2 = triangle_indexes[i][1];
- v3 = triangle_indexes[i][2];
- if (isect_ray_tri_v3(ray_start, ray_normal, bb->vec[v1], bb->vec[v2], bb->vec[v3], &lambda, NULL) &&
- (!r_lambda || *r_lambda > lambda))
- {
- result = true;
- if (r_lambda) {
- *r_lambda = lambda;
- }
- }
- }
-
- return result;
-}
-
static int pc_cmp(const void *a, const void *b)
{
const LinkData *ad = a, *bd = b;
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index b5e1ded35bb..ccf2aec5c7a 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -32,6 +32,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
+#include "BLI_string_utils.h"
#include "DNA_armature_types.h"
#include "DNA_cloth_types.h"
@@ -623,7 +624,7 @@ void BKE_object_defgroup_mirror_selection(
if (dg_selection[i]) {
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, defgroup->name, false);
+ BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
i_mirr = STREQ(name_flip, defgroup->name) ? i : defgroup_name_index(ob, name_flip);
if ((i_mirr >= 0 && i_mirr < defbase_tot) && (dg_flags_sel[i_mirr] == false)) {
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index ee435051151..943dc781246 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -4328,12 +4328,12 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
{
ParticleTarget *pt;
- func(psys, (ID **)&psys->part, userdata, IDWALK_USER | IDWALK_NEVER_NULL);
- func(psys, (ID **)&psys->target_ob, userdata, IDWALK_NOP);
- func(psys, (ID **)&psys->parent, userdata, IDWALK_NOP);
+ func(psys, (ID **)&psys->part, userdata, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
+ func(psys, (ID **)&psys->target_ob, userdata, IDWALK_CB_NOP);
+ func(psys, (ID **)&psys->parent, userdata, IDWALK_CB_NOP);
for (pt = psys->targets.first; pt; pt = pt->next) {
- func(psys, (ID **)&pt->ob, userdata, IDWALK_NOP);
+ func(psys, (ID **)&pt->ob, userdata, IDWALK_CB_NOP);
}
/* Even though psys->part should never be NULL, this can happen as an exception during deletion.
@@ -4343,7 +4343,7 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
int p;
for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) {
- func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_NOP);
+ func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_CB_NOP);
}
}
}
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index b5f34a29ebb..5353cc26295 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -974,14 +974,14 @@ void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw)
void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata)
{
- func(rbw, (ID **)&rbw->group, userdata, IDWALK_NOP);
- func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_NOP);
- func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_NOP);
+ func(rbw, (ID **)&rbw->group, userdata, IDWALK_CB_NOP);
+ func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_CB_NOP);
+ func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_CB_NOP);
if (rbw->objects) {
int i;
for (i = 0; i < rbw->numbodies; i++) {
- func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_NOP);
+ func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_CB_NOP);
}
}
}
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index fa221348932..7920d8b5696 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -992,19 +992,19 @@ void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *use
bSensor *sensor;
for (sensor = senslist->first; sensor; sensor = sensor->next) {
- func(sensor, (ID **)&sensor->ob, userdata, IDWALK_NOP);
+ func(sensor, (ID **)&sensor->ob, userdata, IDWALK_CB_NOP);
switch (sensor->type) {
case SENS_TOUCH: /* DEPRECATED */
{
bTouchSensor *ts = sensor->data;
- func(sensor, (ID **)&ts->ma, userdata, IDWALK_NOP);
+ func(sensor, (ID **)&ts->ma, userdata, IDWALK_CB_NOP);
break;
}
case SENS_MESSAGE:
{
bMessageSensor *ms = sensor->data;
- func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_NOP);
+ func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_CB_NOP);
break;
}
case SENS_ALWAYS:
@@ -1035,7 +1035,7 @@ void BKE_sca_controllers_id_loop(ListBase *contlist, SCAControllerIDFunc func, v
case CONT_PYTHON:
{
bPythonCont *pc = controller->data;
- func(controller, (ID **)&pc->text, userdata, IDWALK_NOP);
+ func(controller, (ID **)&pc->text, userdata, IDWALK_CB_NOP);
break;
}
case CONT_LOGIC_AND:
@@ -1056,89 +1056,89 @@ void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void *
bActuator *actuator;
for (actuator = actlist->first; actuator; actuator = actuator->next) {
- func(actuator, (ID **)&actuator->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&actuator->ob, userdata, IDWALK_CB_NOP);
switch (actuator->type) {
case ACT_ADD_OBJECT: /* DEPRECATED */
{
bAddObjectActuator *aoa = actuator->data;
- func(actuator, (ID **)&aoa->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&aoa->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_ACTION:
{
bActionActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->act, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&aa->act, userdata, IDWALK_CB_NOP);
break;
}
case ACT_SOUND:
{
bSoundActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->sound, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&sa->sound, userdata, IDWALK_CB_NOP);
break;
}
case ACT_EDIT_OBJECT:
{
bEditObjectActuator *eoa = actuator->data;
- func(actuator, (ID **)&eoa->ob, userdata, IDWALK_NOP);
- func(actuator, (ID **)&eoa->me, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&eoa->ob, userdata, IDWALK_CB_NOP);
+ func(actuator, (ID **)&eoa->me, userdata, IDWALK_CB_NOP);
break;
}
case ACT_SCENE:
{
bSceneActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->scene, userdata, IDWALK_NOP);
- func(actuator, (ID **)&sa->camera, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&sa->scene, userdata, IDWALK_CB_NOP);
+ func(actuator, (ID **)&sa->camera, userdata, IDWALK_CB_NOP);
break;
}
case ACT_PROPERTY:
{
bPropertyActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_OBJECT:
{
bObjectActuator *oa = actuator->data;
- func(actuator, (ID **)&oa->reference, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&oa->reference, userdata, IDWALK_CB_NOP);
break;
}
case ACT_CAMERA:
{
bCameraActuator *ca = actuator->data;
- func(actuator, (ID **)&ca->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&ca->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_MESSAGE:
{
bMessageActuator *ma = actuator->data;
- func(actuator, (ID **)&ma->toObject, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&ma->toObject, userdata, IDWALK_CB_NOP);
break;
}
case ACT_2DFILTER:
{
bTwoDFilterActuator *tdfa = actuator->data;
- func(actuator, (ID **)&tdfa->text, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&tdfa->text, userdata, IDWALK_CB_NOP);
break;
}
case ACT_PARENT:
{
bParentActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_ARMATURE:
{
bArmatureActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->target, userdata, IDWALK_NOP);
- func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&aa->target, userdata, IDWALK_CB_NOP);
+ func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_CB_NOP);
break;
}
case ACT_STEERING:
{
bSteeringActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->target, userdata, IDWALK_NOP);
- func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&sa->target, userdata, IDWALK_CB_NOP);
+ func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_CB_NOP);
break;
}
/* Note: some types seems to be non-implemented? ACT_LAMP, ACT_MATERIAL... */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 8938e6c391f..d9439328c83 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -56,6 +56,7 @@
#include "BLI_utildefines.h"
#include "BLI_callbacks.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLI_task.h"
@@ -286,13 +287,16 @@ Scene *BKE_scene_copy(Main *bmain, 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);
}
-
+
+ /* duplicate Grease Pencil interpolation curve */
+ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
}
/* make a private copy of the avicodecdata */
@@ -439,12 +443,17 @@ void BKE_scene_free(Scene *sce)
BKE_paint_free(&sce->toolsettings->uvsculpt->paint);
MEM_freeN(sce->toolsettings->uvsculpt);
}
+ BKE_paint_free(&sce->toolsettings->imapaint.paint);
+
/* 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);
-
+
+ /* free Grease Pencil interpolation curve */
+ if (sce->toolsettings->gp_interpolate.custom_ipo) {
+ curvemapping_free(sce->toolsettings->gp_interpolate.custom_ipo);
+ }
+
MEM_freeN(sce->toolsettings);
sce->toolsettings = NULL;
}
@@ -2047,6 +2056,8 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *
return false;
}
+ BKE_freestyle_config_free(&srl->freestyleConfig);
+
if (srl->prop) {
IDP_FreeProperty(srl->prop);
MEM_freeN(srl->prop);
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index 95c6b7736e1..89c2f76c661 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -34,8 +34,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 672857e88fe..88575c7d3be 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -235,8 +235,9 @@ Text *BKE_text_add(Main *bmain, const char *name)
/* to a valid utf-8 sequences */
int txt_extended_ascii_as_utf8(char **str)
{
- int bad_char, added = 0, i = 0;
- int length = strlen(*str);
+ ptrdiff_t bad_char, i = 0;
+ const ptrdiff_t length = (ptrdiff_t)strlen(*str);
+ int added = 0;
while ((*str)[i]) {
if ((bad_char = BLI_utf8_invalid_byte(*str + i, length - i)) == -1)
@@ -248,7 +249,7 @@ int txt_extended_ascii_as_utf8(char **str)
if (added != 0) {
char *newstr = MEM_mallocN(length + added + 1, "text_line");
- int mi = 0;
+ ptrdiff_t mi = 0;
i = 0;
while ((*str)[i]) {
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 96ab8693122..990d250b854 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -49,8 +49,8 @@
#include "BLI_math.h"
#include "BLI_math_base.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index a90b1dee927..1c056cda68d 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -42,8 +42,8 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_ghash.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -625,17 +625,17 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf)
*/
size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float);
grayscale->channels = 1;
- if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image"))) {
+ if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
grayscale->mall |= IB_rectfloat;
grayscale->flags |= IB_rectfloat;
- }
- for (i = 0; i < grayscale->x * grayscale->y; ++i) {
- const float *pixel = ibuf->rect_float + ibuf->channels * i;
+ for (i = 0; i < grayscale->x * grayscale->y; ++i) {
+ const float *pixel = ibuf->rect_float + ibuf->channels * i;
- grayscale->rect_float[i] = 0.2126f * pixel[0] +
- 0.7152f * pixel[1] +
- 0.0722f * pixel[2];
+ grayscale->rect_float[i] = 0.2126f * pixel[0] +
+ 0.7152f * pixel[1] +
+ 0.0722f * pixel[2];
+ }
}
return grayscale;
@@ -653,14 +653,14 @@ static void ibuf_to_float_image(const ImBuf *ibuf, libmv_FloatImage *float_image
static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image)
{
ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0);
- size_t size = (size_t)ibuf->x * (size_t)ibuf->y *
- float_image->channels * sizeof(float);
+ size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float);
ibuf->channels = float_image->channels;
- if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image"))) {
+ if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
ibuf->mall |= IB_rectfloat;
ibuf->flags |= IB_rectfloat;
+
+ memcpy(ibuf->rect_float, float_image->buffer, size);
}
- memcpy(ibuf->rect_float, float_image->buffer, size);
return ibuf;
}
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index d33c2cb3279..4a85e859c16 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -293,6 +293,10 @@ void isect_ray_aabb_v3_precalc(
bool isect_ray_aabb_v3(
const struct IsectRayAABB_Precalc *data,
const float bb_min[3], const float bb_max[3], float *tmin);
+bool isect_ray_aabb_v3_simple(
+ const float orig[3], const float dir[3],
+ const float bb_min[3], const float bb_max[3],
+ float *tmin, float *tmax);
struct NearestRayToAABB_Precalc {
float ray_origin[3];
@@ -389,6 +393,8 @@ void box_minmax_bounds_m4(float min[3], float max[3],
void map_to_tube(float *r_u, float *r_v, const float x, const float y, const float z);
void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const float z);
+void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3]);
+void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const float axis[3], const float angle);
/********************************** Normals **********************************/
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index 1a626ff44bd..baa1f792018 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -91,13 +91,8 @@ bool BLI_testextensie_glob(const char *str, const char *ext_fnmatch) ATTR_NONNUL
bool BLI_replace_extension(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
bool BLI_ensure_extension(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL();
-bool BLI_uniquename(struct ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int len);
-bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name),
- void *arg, const char *defname, char delim, char *name, int name_len);
-void BLI_newname(char *name, int add);
int BLI_stringdec(const char *string, char *head, char *start, unsigned short *numlen);
void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic);
-int BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
/* removes trailing slash */
void BLI_cleanup_file(const char *relabase, char *path) ATTR_NONNULL(2);
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index 0740b574c1a..32504a88b48 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -36,8 +36,8 @@ extern "C" {
char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
char *BLI_strncat_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
-int BLI_utf8_invalid_byte(const char *str, int length) ATTR_NONNULL();
-int BLI_utf8_invalid_strip(char *str, int length) ATTR_NONNULL();
+ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL();
+int BLI_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL();
int BLI_str_utf8_size(const char *p) ATTR_NONNULL(); /* warning, can return -1 on bad chars */
int BLI_str_utf8_size_safe(const char *p) ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
new file mode 100644
index 00000000000..bb19ed574bb
--- /dev/null
+++ b/source/blender/blenlib/BLI_string_utils.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.
+ *
+ * The Original Code is Copyright (C) 2017 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_STRING_UTILS_H__
+#define __BLI_STRING_UTILS_H__
+
+/** \file BLI_string_utils.h
+ * \ingroup bli
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_compiler_attrs.h"
+
+struct ListBase;
+
+typedef bool (*UniquenameCheckCallback)(void *arg, const char *name);
+
+size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
+
+void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len);
+void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len);
+
+void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len);
+
+bool BLI_uniquename_cb(
+ UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len);
+bool BLI_uniquename(
+ struct ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_STRING_UTILS_H__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 6e717a3ae7e..3277519c66e 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -109,6 +109,7 @@ set(SRC
intern/string.c
intern/string_cursor_utf8.c
intern/string_utf8.c
+ intern/string_utils.c
intern/system.c
intern/task.c
intern/threads.c
@@ -195,6 +196,7 @@ set(SRC
BLI_string.h
BLI_string_cursor_utf8.h
BLI_string_utf8.h
+ BLI_string_utils.h
BLI_sys_types.h
BLI_system.h
BLI_task.h
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 74ede1e7559..aeb6a550cd9 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -2309,6 +2309,34 @@ bool isect_ray_aabb_v3(
return true;
}
+/*
+ * Test a bounding box (AABB) for ray intersection
+ * assumes the ray is already local to the boundbox space
+ */
+bool isect_ray_aabb_v3_simple(
+ const float orig[3], const float dir[3],
+ const float bb_min[3], const float bb_max[3],
+ float *tmin, float *tmax)
+{
+ double t[7];
+ float hit_dist[2];
+ t[1] = (double)(bb_min[0] - orig[0]) / dir[0];
+ t[2] = (double)(bb_max[0] - orig[0]) / dir[0];
+ t[3] = (double)(bb_min[1] - orig[1]) / dir[1];
+ t[4] = (double)(bb_max[1] - orig[1]) / dir[1];
+ t[5] = (double)(bb_min[2] - orig[2]) / dir[2];
+ t[6] = (double)(bb_max[2] - orig[2]) / dir[2];
+ hit_dist[0] = (float)fmax(fmax(fmin(t[1], t[2]), fmin(t[3], t[4])), fmin(t[5], t[6]));
+ hit_dist[1] = (float)fmin(fmin(fmax(t[1], t[2]), fmax(t[3], t[4])), fmax(t[5], t[6]));
+ if ((hit_dist[1] < 0 || hit_dist[0] > hit_dist[1]))
+ return false;
+ else {
+ if (tmin) *tmin = hit_dist[0];
+ if (tmax) *tmax = hit_dist[1];
+ return true;
+ }
+}
+
void dist_squared_ray_to_aabb_v3_precalc(
struct NearestRayToAABB_Precalc *data,
const float ray_origin[3], const float ray_direction[3])
@@ -4048,6 +4076,26 @@ void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const f
}
}
+void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3])
+{
+ float target[3] = {0.0f, 0.0f, 1.0f};
+ float axis[3];
+
+ cross_v3_v3v3(axis, no, target);
+ normalize_v3(axis);
+
+ map_to_plane_axis_angle_v2_v3v3fl(r_co, co, axis, angle_normalized_v3v3(no, target));
+}
+
+void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const float axis[3], const float angle)
+{
+ float tmp[3];
+
+ rotate_normalized_v3_v3v3fl(tmp, co, axis, angle);
+
+ copy_v2_v2(r_co, tmp);
+}
+
/********************************* Normals **********************************/
void accumulate_vertex_normals_tri(
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index f0d0bd00dea..6644e6605a1 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -63,9 +63,6 @@
#include "MEM_guardedalloc.h"
-/* local */
-#define UNIQUE_NAME_MAX 128
-
/* Declarations */
#ifdef WIN32
@@ -147,162 +144,6 @@ void BLI_stringenc(char *string, const char *head, const char *tail, unsigned sh
sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
}
-/**
- * Looks for a numeric suffix preceded by delim character on the end of
- * name, puts preceding part into *left and value of suffix into *nr.
- * Returns the length of *left.
- *
- * Foo.001 -> "Foo", 1
- * Returning the length of "Foo"
- *
- * \param left Where to return copy of part preceding delim
- * \param nr Where to return value of numeric suffix
- * \param name String to split
- * \param delim Delimiter character
- * \return Length of \a left
- */
-int BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
-{
- const int name_len = strlen(name);
-
- *nr = 0;
- memcpy(left, name, (name_len + 1) * sizeof(char));
-
- /* name doesn't end with a delimiter "foo." */
- if ((name_len > 1 && name[name_len - 1] == delim) == 0) {
- int a = name_len;
- while (a--) {
- if (name[a] == delim) {
- left[a] = '\0'; /* truncate left part here */
- *nr = atol(name + a + 1);
- /* casting down to an int, can overflow for large numbers */
- if (*nr < 0)
- *nr = 0;
- return a;
- }
- else if (isdigit(name[a]) == 0) {
- /* non-numeric suffix - give up */
- break;
- }
- }
- }
-
- return name_len;
-}
-
-/**
- * Ensures name is unique (according to criteria specified by caller in unique_check callback),
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param unique_check Return true if name is not unique
- * \param arg Additional arg to unique_check--meaning is up to caller
- * \param defname To initialize name if latter is empty
- * \param delim Delimits numeric suffix in name
- * \param name Name to be ensured unique
- * \param name_len Maximum length of name area
- * \return true if there if the name was changed
- */
-bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name),
- void *arg, const char *defname, char delim, char *name, int name_len)
-{
- if (name[0] == '\0') {
- BLI_strncpy(name, defname, name_len);
- }
-
- if (unique_check(arg, name)) {
- char numstr[16];
- char tempname[UNIQUE_NAME_MAX];
- char left[UNIQUE_NAME_MAX];
- int number;
- int len = BLI_split_name_num(left, &number, name, delim);
- do {
- /* add 1 to account for \0 */
- const int numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1;
-
- /* highly unlikely the string only has enough room for the number
- * but support anyway */
- if ((len == 0) || (numlen >= name_len)) {
- /* number is know not to be utf-8 */
- BLI_strncpy(tempname, numstr, name_len);
- }
- else {
- char *tempname_buf;
- tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen);
- memcpy(tempname_buf, numstr, numlen);
- }
- } while (unique_check(arg, tempname));
-
- BLI_strncpy(name, tempname, name_len);
-
- return true;
- }
-
- return false;
-}
-
-/* little helper macro for BLI_uniquename */
-#ifndef GIVE_STRADDR
-# define GIVE_STRADDR(data, offset) ( ((char *)data) + offset)
-#endif
-
-/* Generic function to set a unique name. It is only designed to be used in situations
- * where the name is part of the struct, and also that the name is at most UNIQUE_NAME_MAX chars long.
- *
- * For places where this is used, see constraint.c for example...
- *
- * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
- * len: maximum length of string (to prevent overflows, etc.)
- * defname: the name that should be used by default if none is specified already
- * delim: the character which acts as a delimiter between parts of the name
- */
-static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
-{
- Link *link;
-
- for (link = list->first; link; link = link->next) {
- if (link != vlink) {
- if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static bool uniquename_unique_check(void *arg, const char *name)
-{
- struct {ListBase *lb; void *vlink; int name_offs; } *data = arg;
- return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
-}
-
-/**
- * Ensures that the specified block has a unique name within the containing list,
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param list List containing the block
- * \param vlink The block to check the name for
- * \param defname To initialize block name if latter is empty
- * \param delim Delimits numeric suffix in name
- * \param name_offs Offset of name within block structure
- * \param name_len Maximum length of name area
- */
-bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int name_len)
-{
- struct {ListBase *lb; void *vlink; int name_offs; } data;
- data.lb = list;
- data.vlink = vlink;
- data.name_offs = name_offs;
-
- assert((name_len > 1) && (name_len <= UNIQUE_NAME_MAX));
-
- /* See if we are given an empty string */
- if (ELEM(NULL, vlink, defname))
- return false;
-
- return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
-}
-
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
/* ******************** string encoding ***************** */
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 0ab11810b48..83d4a75952f 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -74,7 +74,7 @@ static const size_t utf8_skip_data[256] = {
*
* \return the offset of the first invalid byte.
*/
-int BLI_utf8_invalid_byte(const char *str, int length)
+ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length)
{
const unsigned char *p, *perr, *pend = (const unsigned char *)str + length;
unsigned char c;
@@ -161,18 +161,24 @@ int BLI_utf8_invalid_byte(const char *str, int length)
utf8_error:
- return (int)((const char *)perr - (const char *)str);
+ return ((const char *)perr - (const char *)str);
}
-int BLI_utf8_invalid_strip(char *str, int length)
+/**
+ * Remove any invalid utf-8 byte (taking into account multi-bytes sequence of course).
+ *
+ * @return number of stripped bytes.
+ */
+int BLI_utf8_invalid_strip(char *str, size_t length)
{
- int bad_char, tot = 0;
+ ptrdiff_t bad_char;
+ int tot = 0;
BLI_assert(str[length] == '\0');
while ((bad_char = BLI_utf8_invalid_byte(str, length)) != -1) {
str += bad_char;
- length -= (bad_char + 1);
+ length -= (size_t)(bad_char + 1);
if (length == 0) {
/* last character bad, strip it */
@@ -182,7 +188,7 @@ int BLI_utf8_invalid_strip(char *str, int length)
}
else {
/* strip, keep looking */
- memmove(str, str + 1, (size_t)length + 1); /* +1 for NULL char! */
+ memmove(str, str + 1, length + 1); /* +1 for NULL char! */
tot++;
}
}
diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c
new file mode 100644
index 00000000000..8d91a55a5ad
--- /dev/null
+++ b/source/blender/blenlib/intern/string_utils.c
@@ -0,0 +1,385 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by the Blender FOundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenlib/intern/string_utils.c
+ * \ingroup bli
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_listBase.h"
+
+
+#ifdef __GNUC__
+# pragma GCC diagnostic error "-Wsign-conversion"
+#endif
+
+/**
+ * Looks for a numeric suffix preceded by delim character on the end of
+ * name, puts preceding part into *left and value of suffix into *nr.
+ * Returns the length of *left.
+ *
+ * Foo.001 -> "Foo", 1
+ * Returning the length of "Foo"
+ *
+ * \param left Where to return copy of part preceding delim
+ * \param nr Where to return value of numeric suffix
+ * \param name String to split
+ * \param delim Delimiter character
+ * \return Length of \a left
+ */
+size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
+{
+ const size_t name_len = strlen(name);
+
+ *nr = 0;
+ memcpy(left, name, (name_len + 1) * sizeof(char));
+
+ /* name doesn't end with a delimiter "foo." */
+ if ((name_len > 1 && name[name_len - 1] == delim) == 0) {
+ size_t a = name_len;
+ while (a--) {
+ if (name[a] == delim) {
+ left[a] = '\0'; /* truncate left part here */
+ *nr = atol(name + a + 1);
+ /* casting down to an int, can overflow for large numbers */
+ if (*nr < 0)
+ *nr = 0;
+ return a;
+ }
+ else if (isdigit(name[a]) == 0) {
+ /* non-numeric suffix - give up */
+ break;
+ }
+ }
+ }
+
+ return name_len;
+}
+
+static bool is_char_sep(const char c)
+{
+ return ELEM(c, '.', ' ', '-', '_');
+}
+
+/**
+ * based on `BLI_split_dirfile()` / `os.path.splitext()`,
+ * `"a.b.c"` -> (`"a.b"`, `".c"`).
+ */
+void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len)
+{
+ size_t len = BLI_strnlen(string, str_len);
+ size_t i;
+
+ r_body[0] = r_suf[0] = '\0';
+
+ for (i = len; i > 0; i--) {
+ if (is_char_sep(string[i])) {
+ BLI_strncpy(r_body, string, i + 1);
+ BLI_strncpy(r_suf, string + i, (len + 1) - i);
+ return;
+ }
+ }
+
+ memcpy(r_body, string, len + 1);
+}
+
+/**
+ * `"a.b.c"` -> (`"a."`, `"b.c"`)
+ */
+void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len)
+{
+ size_t len = BLI_strnlen(string, str_len);
+ size_t i;
+
+ r_body[0] = r_pre[0] = '\0';
+
+ for (i = 1; i < len; i++) {
+ if (is_char_sep(string[i])) {
+ i++;
+ BLI_strncpy(r_pre, string, i + 1);
+ BLI_strncpy(r_body, string + i, (len + 1) - i);
+ return;
+ }
+ }
+
+ BLI_strncpy(r_body, string, len);
+}
+
+/**
+ * Finds the best possible flipped (left/right) name. For renaming; check for unique names afterwards.
+ *
+ * \param r_name flipped name, assumed to be a pointer to a string of at least \a name_len size.
+ * \param from_name original name, assumed to be a pointer to a string of at least \a name_len size.
+ * \param strip_number If set, remove number extensions.
+ */
+void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len)
+{
+ size_t len;
+ char *prefix = alloca(name_len); /* The part before the facing */
+ char *suffix = alloca(name_len); /* The part after the facing */
+ char *replace = alloca(name_len); /* The replacement string */
+ char *number = alloca(name_len); /* The number extension string */
+ char *index = NULL;
+ bool is_set = false;
+
+ *prefix = *suffix = *replace = *number = '\0';
+
+ /* always copy the name, since this can be called with an uninitialized string */
+ BLI_strncpy(r_name, from_name, name_len);
+
+ len = BLI_strnlen(from_name, name_len);
+ if (len < 3) {
+ /* we don't do names like .R or .L */
+ return;
+ }
+
+ /* We first check the case with a .### extension, let's find the last period */
+ if (isdigit(r_name[len - 1])) {
+ index = strrchr(r_name, '.'); // last occurrence
+ if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever!
+ if (strip_number == false) {
+ BLI_strncpy(number, index, name_len);
+ }
+ *index = 0;
+ len = BLI_strnlen(r_name, name_len);
+ }
+ }
+
+ BLI_strncpy(prefix, r_name, name_len);
+
+ /* first case; separator . - _ with extensions r R l L */
+ if ((len > 1) && is_char_sep(r_name[len - 2])) {
+ is_set = true;
+ switch (r_name[len - 1]) {
+ case 'l':
+ prefix[len - 1] = 0;
+ strcpy(replace, "r");
+ break;
+ case 'r':
+ prefix[len - 1] = 0;
+ strcpy(replace, "l");
+ break;
+ case 'L':
+ prefix[len - 1] = 0;
+ strcpy(replace, "R");
+ break;
+ case 'R':
+ prefix[len - 1] = 0;
+ strcpy(replace, "L");
+ break;
+ default:
+ is_set = false;
+ }
+ }
+
+ /* case; beginning with r R l L, with separator after it */
+ if (!is_set && is_char_sep(r_name[1])) {
+ is_set = true;
+ switch (r_name[0]) {
+ case 'l':
+ strcpy(replace, "r");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ case 'r':
+ strcpy(replace, "l");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ case 'L':
+ strcpy(replace, "R");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ case 'R':
+ strcpy(replace, "L");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ default:
+ is_set = false;
+ }
+ }
+
+ if (!is_set && len > 5) {
+ /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
+ if (((index = BLI_strcasestr(prefix, "right")) == prefix) ||
+ (index == prefix + len - 5))
+ {
+ is_set = true;
+ if (index[0] == 'r') {
+ strcpy(replace, "left");
+ }
+ else {
+ strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
+ }
+ *index = 0;
+ BLI_strncpy(suffix, index + 5, name_len);
+ }
+ else if (((index = BLI_strcasestr(prefix, "left")) == prefix) ||
+ (index == prefix + len - 4))
+ {
+ is_set = true;
+ if (index[0] == 'l') {
+ strcpy(replace, "right");
+ }
+ else {
+ strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
+ }
+ *index = 0;
+ BLI_strncpy(suffix, index + 4, name_len);
+ }
+ }
+
+ BLI_snprintf(r_name, name_len, "%s%s%s%s", prefix, replace, suffix, number);
+}
+
+
+/* Unique name utils. */
+
+/**
+ * Ensures name is unique (according to criteria specified by caller in unique_check callback),
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param unique_check Return true if name is not unique
+ * \param arg Additional arg to unique_check--meaning is up to caller
+ * \param defname To initialize name if latter is empty
+ * \param delim Delimits numeric suffix in name
+ * \param name Name to be ensured unique
+ * \param name_len Maximum length of name area
+ * \return true if there if the name was changed
+ */
+bool BLI_uniquename_cb(
+ UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len)
+{
+ if (name[0] == '\0') {
+ BLI_strncpy(name, defname, name_len);
+ }
+
+ if (unique_check(arg, name)) {
+ char numstr[16];
+ char *tempname = alloca(name_len);
+ char *left = alloca(name_len);
+ int number;
+ size_t len = BLI_split_name_num(left, &number, name, delim);
+ do {
+ /* add 1 to account for \0 */
+ const size_t numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1;
+
+ /* highly unlikely the string only has enough room for the number
+ * but support anyway */
+ if ((len == 0) || (numlen >= name_len)) {
+ /* number is know not to be utf-8 */
+ BLI_strncpy(tempname, numstr, name_len);
+ }
+ else {
+ char *tempname_buf;
+ tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen);
+ memcpy(tempname_buf, numstr, numlen);
+ }
+ } while (unique_check(arg, tempname));
+
+ BLI_strncpy(name, tempname, name_len);
+
+ return true;
+ }
+
+ return false;
+}
+
+/* little helper macro for BLI_uniquename */
+#ifndef GIVE_STRADDR
+# define GIVE_STRADDR(data, offset) ( ((char *)data) + offset)
+#endif
+
+/* Generic function to set a unique name. It is only designed to be used in situations
+ * where the name is part of the struct.
+ *
+ * For places where this is used, see constraint.c for example...
+ *
+ * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
+ * len: maximum length of string (to prevent overflows, etc.)
+ * defname: the name that should be used by default if none is specified already
+ * delim: the character which acts as a delimiter between parts of the name
+ */
+static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
+{
+ Link *link;
+
+ for (link = list->first; link; link = link->next) {
+ if (link != vlink) {
+ if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool uniquename_unique_check(void *arg, const char *name)
+{
+ struct {ListBase *lb; void *vlink; int name_offs; } *data = arg;
+ return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
+}
+
+/**
+ * Ensures that the specified block has a unique name within the containing list,
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param list List containing the block
+ * \param vlink The block to check the name for
+ * \param defname To initialize block name if latter is empty
+ * \param delim Delimits numeric suffix in name
+ * \param name_offs Offset of name within block structure
+ * \param name_len Maximum length of name area
+ */
+bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t name_len)
+{
+ struct {ListBase *lb; void *vlink; int name_offs; } data;
+ data.lb = list;
+ data.vlink = vlink;
+ data.name_offs = name_offs;
+
+ BLI_assert(name_len > 1);
+
+ /* See if we are given an empty string */
+ if (ELEM(NULL, vlink, defname))
+ return false;
+
+ return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
+}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 24361a68bb2..8a3e493088b 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3244,6 +3244,11 @@ static void direct_link_constraints(FileData *fd, ListBase *lb)
con->flag |= CONSTRAINT_SPACEONCE;
break;
}
+ case CONSTRAINT_TYPE_TRANSFORM_CACHE:
+ {
+ bTransformCacheConstraint *data = con->data;
+ data->reader = NULL;
+ }
}
}
}
@@ -4703,12 +4708,12 @@ static void direct_link_latt(FileData *fd, Lattice *lt)
/* ************ READ OBJECT ***************** */
static void lib_link_modifiers__linkModifiers(
- void *userData, Object *ob, ID **idpoin, int cd_flag)
+ void *userData, Object *ob, ID **idpoin, int cb_flag)
{
FileData *fd = userData;
*idpoin = newlibadr(fd, ob->id.lib, *idpoin);
- if (*idpoin != NULL && (cd_flag & IDWALK_USER) != 0) {
+ if (*idpoin != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
id_us_plus_no_lib(*idpoin);
}
}
@@ -5932,6 +5937,7 @@ 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) {
@@ -5948,6 +5954,12 @@ static void direct_link_scene(FileData *fd, Scene *sce)
direct_link_curvemapping(fd, brush->cur_jitter);
}
}
+
+ /* relink grease pencil interpolation curves */
+ sce->toolsettings->gp_interpolate.custom_ipo = newdataadr(fd, sce->toolsettings->gp_interpolate.custom_ipo);
+ if (sce->toolsettings->gp_interpolate.custom_ipo) {
+ direct_link_curvemapping(fd, sce->toolsettings->gp_interpolate.custom_ipo);
+ }
}
if (sce->ed) {
@@ -8386,9 +8398,10 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
static void do_versions_after_linking(Main *main)
{
- UNUSED_VARS(main);
// printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name,
// main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile);
+
+ do_versions_after_linking_270(main);
}
static void lib_link_all(FileData *fd, Main *main)
@@ -9295,7 +9308,7 @@ static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
}
static void expand_object_expandModifiers(
- void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
+ void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cb_flag))
{
struct { FileData *fd; Main *mainvar; } *data= userData;
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 7719aaa2b0d..d97bef13a78 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -170,5 +170,7 @@ void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *
void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *main);
void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *main);
+void do_versions_after_linking_270(struct Main *main);
+
#endif
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 907baab0aee..ab3d14af882 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -56,6 +56,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 410e186ca2c..7df5a77595a 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_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
@@ -58,6 +59,7 @@
#include "DNA_genfile.h"
+#include "BKE_animsys.h"
#include "BKE_colortools.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -78,6 +80,9 @@
#include "NOD_composite.h"
+#include "NOD_common.h"
+#include "NOD_socket.h"
+
#include "readfile.h"
#include "MEM_guardedalloc.h"
@@ -197,6 +202,54 @@ static void do_version_bones_super_bbone(ListBase *lb)
}
}
+/* TODO(sergey): Consider making it somewhat more generic function in BLI_anim.h. */
+static void anim_change_prop_name(FCurve *fcu,
+ const char *prefix,
+ const char *old_prop_name,
+ const char *new_prop_name)
+{
+ const char *old_path = BLI_sprintfN("%s.%s", prefix, old_prop_name);
+ if (STREQ(fcu->rna_path, old_path)) {
+ MEM_freeN(fcu->rna_path);
+ fcu->rna_path = BLI_sprintfN("%s.%s", prefix, new_prop_name);
+ }
+ MEM_freeN((char *)old_path);
+}
+
+static void do_version_hue_sat_node(bNodeTree *ntree, bNode *node)
+{
+ if (node->storage == NULL) {
+ return;
+ }
+
+ /* Make sure new sockets are properly created. */
+ node_verify_socket_templates(ntree, node);
+ /* Convert value from old storage to new sockets. */
+ NodeHueSat *nhs = node->storage;
+ bNodeSocket *hue = nodeFindSocket(node, SOCK_IN, "Hue"),
+ *saturation = nodeFindSocket(node, SOCK_IN, "Saturation"),
+ *value = nodeFindSocket(node, SOCK_IN, "Value");
+ ((bNodeSocketValueFloat *)hue->default_value)->value = nhs->hue;
+ ((bNodeSocketValueFloat *)saturation->default_value)->value = nhs->sat;
+ ((bNodeSocketValueFloat *)value->default_value)->value = nhs->val;
+ /* Take care of possible animation. */
+ AnimData *adt = BKE_animdata_from_id(&ntree->id);
+ if (adt != NULL && adt->action != NULL) {
+ const char *prefix = BLI_sprintfN("nodes[\"%s\"]", node->name);
+ for (FCurve *fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (STRPREFIX(fcu->rna_path, prefix)) {
+ anim_change_prop_name(fcu, prefix, "color_hue", "inputs[1].default_value");
+ anim_change_prop_name(fcu, prefix, "color_saturation", "inputs[2].default_value");
+ anim_change_prop_name(fcu, prefix, "color_value", "inputs[3].default_value");
+ }
+ }
+ MEM_freeN((char *)prefix);
+ }
+ /* Free storage, it is no longer used. */
+ MEM_freeN(node->storage);
+ node->storage = NULL;
+}
+
void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
if (!MAIN_VERSION_ATLEAST(main, 270, 0)) {
@@ -1493,6 +1546,36 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
for (Brush *br = main->brush.first; br; br = br->id.next) {
br->fill_threshold /= sqrt_3;
}
+
+ /* Custom motion paths */
+ if (!DNA_struct_elem_find(fd->filesdna, "bMotionPath", "int", "line_thickness")) {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ bMotionPath *mpath;
+ bPoseChannel *pchan;
+ mpath = ob->mpath;
+ if (mpath) {
+ mpath->color[0] = 1.0f;
+ mpath->color[1] = 0.0f;
+ mpath->color[2] = 0.0f;
+ mpath->line_thickness = 1;
+ mpath->flag |= MOTIONPATH_FLAG_LINES;
+ }
+ /* bones motion path */
+ if (ob->pose) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ mpath = pchan->mpath;
+ if (mpath) {
+ mpath->color[0] = 1.0f;
+ mpath->color[1] = 0.0f;
+ mpath->color[2] = 0.0f;
+ mpath->line_thickness = 1;
+ mpath->flag |= MOTIONPATH_FLAG_LINES;
+ }
+ }
+ }
+ }
+ }
}
/* To be added to next subversion bump! */
@@ -1536,3 +1619,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
}
}
+
+void do_versions_after_linking_270(Main *main)
+{
+ /* To be added to next subversion bump! */
+ {
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ ntreeSetTypes(NULL, ntree);
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_HUE_SAT) {
+ do_version_hue_sat_node(ntree, node);
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
+ }
+}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 343aed390e6..5794c99c1bb 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -2691,6 +2691,10 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
write_curvemapping(wd, brush->cur_jitter);
}
}
+ /* write grease-pencil custom ipo curve to file */
+ if (tos->gp_interpolate.custom_ipo) {
+ write_curvemapping(wd, tos->gp_interpolate.custom_ipo);
+ }
write_paint(wd, &tos->imapaint.paint);
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 132a7ccd4fa..e46a31cb2e9 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -387,15 +387,11 @@ BMFace *BM_face_create_ngon_verts(
*
* \note Since this is a vcloud there is no direction.
*/
-BMFace *BM_face_create_ngon_vcloud(
- BMesh *bm, BMVert **vert_arr, int len,
- const BMFace *f_example, const eBMCreateFlag create_flag)
+void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
{
struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len);
- BMFace *f;
-
float totv_inv = 1.0f / (float)len;
int i = 0;
@@ -470,26 +466,9 @@ BMFace *BM_face_create_ngon_vcloud(
/* now calculate every points angle around the normal (signed) */
for (i = 0; i < len; i++) {
- float co[3];
- float proj_vec[3];
- float angle;
-
- /* center relative vec */
- sub_v3_v3v3(co, vert_arr[i]->co, cent);
-
- /* align to plane */
- project_v3_v3v3(proj_vec, co, nor);
- sub_v3_v3(co, proj_vec);
-
- /* now 'co' is valid - we can compare its angle against the far vec */
- angle = angle_v3v3(far_vec, co);
-
- if (dot_v3v3(co, sign_vec) < 0.0f) {
- angle = -angle;
- }
-
- vang[i].sort_value = angle;
+ vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor);
vang[i].data = i;
+ vert_arr_map[i] = vert_arr[i];
}
/* sort by angle and magic! - we have our ngon */
@@ -497,14 +476,9 @@ BMFace *BM_face_create_ngon_vcloud(
/* --- */
- /* create edges and find the winding (if faces are attached to any existing edges) */
for (i = 0; i < len; i++) {
- vert_arr_map[i] = vert_arr[vang[i].data];
+ vert_arr[i] = vert_arr_map[vang[i].data];
}
-
- f = BM_face_create_ngon_verts(bm, vert_arr_map, len, f_example, create_flag, true, true);
-
- return f;
}
/*************************************************************/
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index 9c6483de42b..a52a17cd2f3 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -34,6 +34,9 @@ bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len);
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len);
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len);
+/* sort before creation */
+void BM_verts_sort_radial_plane(BMVert **vert_arr, int len);
+
BMFace *BM_face_create_quad_tri(
BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
const BMFace *f_example, const eBMCreateFlag create_flag);
@@ -50,10 +53,6 @@ BMFace *BM_face_create_ngon_verts(
const BMFace *f_example, const eBMCreateFlag create_flag,
const bool calc_winding, const bool create_edges);
-BMFace *BM_face_create_ngon_vcloud(
- BMesh *bm, BMVert **vert_arr, int len,
- const BMFace *f_example, const eBMCreateFlag create_flag);
-
void BM_elem_attrs_copy_ex(
BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v,
const char hflag_mask);
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 7178a8132d2..7f2032d5f53 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -70,7 +70,7 @@ static void recount_totsels(BMesh *bm)
}
}
-/** \name BMesh helper functions for selection flushing.
+/** \name BMesh helper functions for selection & hide flushing.
* \{ */
static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
@@ -102,6 +102,20 @@ static bool bm_vert_is_edge_select_any(const BMVert *v)
}
#endif
+static bool bm_vert_is_edge_visible_any(const BMVert *v)
+{
+ if (v->e) {
+ const BMEdge *e_iter, *e_first;
+ e_iter = e_first = v->e;
+ do {
+ if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
+ return true;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ return false;
+}
+
static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
{
const BMLoop *l_iter = l_first;
@@ -131,6 +145,20 @@ static bool bm_edge_is_face_select_any(const BMEdge *e)
}
#endif
+static bool bm_edge_is_face_visible_any(const BMEdge *e)
+{
+ if (e->l) {
+ const BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
+ do {
+ if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ return false;
+}
+
/** \} */
/**
@@ -1198,87 +1226,111 @@ void BM_mesh_elem_hflag_enable_all(
/***************** Mesh Hiding stuff *********** */
+/**
+ * Hide unless any connected elements are visible.
+ * Run this after hiding a connected edge or face.
+ */
static void vert_flush_hide_set(BMVert *v)
{
- BMIter iter;
- BMEdge *e;
- bool hide = true;
-
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- hide = hide && BM_elem_flag_test(e, BM_ELEM_HIDDEN);
- }
-
- BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
+ BM_elem_flag_set(v, BM_ELEM_HIDDEN, !bm_vert_is_edge_visible_any(v));
}
-static void edge_flush_hide(BMEdge *e)
+/**
+ * Hide unless any connected elements are visible.
+ * Run this after hiding a connected face.
+ */
+static void edge_flush_hide_set(BMEdge *e)
{
- BMIter iter;
- BMFace *f;
- bool hide = true;
-
- BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
- hide = hide && BM_elem_flag_test(f, BM_ELEM_HIDDEN);
- }
-
- BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
+ BM_elem_flag_set(e, BM_ELEM_HIDDEN, !bm_edge_is_face_visible_any(e));
}
void BM_vert_hide_set(BMVert *v, const bool hide)
{
/* vert hiding: vert + surrounding edges and faces */
- BMIter iter, fiter;
- BMEdge *e;
- BMFace *f;
-
BLI_assert(v->head.htype == BM_VERT);
+ if (hide) {
+ BLI_assert(!BM_elem_flag_test(v, BM_ELEM_SELECT));
+ }
BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
-
- BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
- }
+ if (v->e) {
+ BMEdge *e_iter, *e_first;
+ e_iter = e_first = v->e;
+ do {
+ BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide);
+ if (e_iter->l) {
+ const BMLoop *l_radial_iter, *l_radial_first;
+ l_radial_iter = l_radial_first = e_iter->l;
+ do {
+ BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide);
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
}
}
void BM_edge_hide_set(BMEdge *e, const bool hide)
{
- BMIter iter;
- BMFace *f;
- /* BMVert *v; */
-
BLI_assert(e->head.htype == BM_EDGE);
+ if (hide) {
+ BLI_assert(!BM_elem_flag_test(e, BM_ELEM_SELECT));
+ }
/* edge hiding: faces around the edge */
- BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
- BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
+ if (e->l) {
+ const BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
+ do {
+ BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide);
+ } while ((l_iter = l_iter->radial_next) != l_first);
}
BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
/* hide vertices if necessary */
- vert_flush_hide_set(e->v1);
- vert_flush_hide_set(e->v2);
+ if (hide) {
+ vert_flush_hide_set(e->v1);
+ vert_flush_hide_set(e->v2);
+ }
+ else {
+ BM_elem_flag_disable(e->v1, BM_ELEM_HIDDEN);
+ BM_elem_flag_disable(e->v2, BM_ELEM_HIDDEN);
+ }
}
void BM_face_hide_set(BMFace *f, const bool hide)
{
- BMIter iter;
- BMLoop *l;
-
BLI_assert(f->head.htype == BM_FACE);
+ if (hide) {
+ BLI_assert(!BM_elem_flag_test(f, BM_ELEM_SELECT));
+ }
BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
- BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
- edge_flush_hide(l->e);
+ if (hide) {
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter;
+
+ l_iter = l_first;
+ do {
+ edge_flush_hide_set(l_iter->e);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ l_iter = l_first;
+ do {
+ vert_flush_hide_set(l_iter->v);
+ } while ((l_iter = l_iter->next) != l_first);
}
+ else {
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter;
- BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
- vert_flush_hide_set(l->v);
+ l_iter = l_first;
+ do {
+ BM_elem_flag_disable(l_iter->e, BM_ELEM_HIDDEN);
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_HIDDEN);
+ } while ((l_iter = l_iter->next) != l_first);
}
}
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index 7b8cb36ab59..a980baf8626 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -290,7 +290,11 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
BMFace *f;
BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv);
- f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE);
+
+ BM_verts_sort_radial_plane(vert_arr, totv);
+
+ /* create edges and find the winding (if faces are attached to any existing edges) */
+ f = BM_face_create_ngon_verts(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE, true, true);
if (f) {
BMO_face_flag_enable(bm, f, ELE_OUT);
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index c52c608e671..e2ff09669d7 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -647,6 +647,10 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
} (void)0
#define VERT_ORIG_GET(_v) \
(const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co)
+ /* memory for the coords isn't given back to the arena,
+ * acceptable in this case since it runs a fixed number of times. */
+#define VERT_ORIG_REMOVE(_v) \
+ BLI_ghash_remove(vert_coords, (_v), NULL, NULL)
for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
@@ -972,7 +976,11 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
v_glue = v_split;
}
else {
- BM_vert_splice(bm, v_glue, v_split);
+ if (BM_vert_splice(bm, v_glue, v_split)) {
+ if (use_vert_coords_orig) {
+ VERT_ORIG_REMOVE(v_split);
+ }
+ }
}
}
}
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 5cd01eff263..3801c9300df 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -35,8 +35,8 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 4f5cf83f5ca..9c26ba83b44 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -69,17 +69,21 @@ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce,
// write bone nodes
bArmature * armature = (bArmature *)ob_arm->data;
- ED_armature_to_edit(armature);
+ bool is_edited = armature->edbo != NULL;
- bArmature *arm = (bArmature *)ob_arm->data;
- for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) {
+ if (!is_edited)
+ ED_armature_to_edit(armature);
+
+ for (Bone *bone = (Bone *)armature->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);
+ if (!is_edited) {
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
+ }
}
void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
index 29c296a896d..36bc176b1a6 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
@@ -37,11 +37,12 @@ HueSaturationValueNode::HueSaturationValueNode(bNode *editorNode) : Node(editorN
void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
- NodeInput *valueSocket = this->getInputSocket(0);
- NodeInput *colorSocket = this->getInputSocket(1);
+ NodeInput *colorSocket = this->getInputSocket(0);
+ NodeInput *hueSocket = this->getInputSocket(1);
+ NodeInput *saturationSocket = this->getInputSocket(2);
+ NodeInput *valueSocket = this->getInputSocket(3);
+ NodeInput *facSocket = this->getInputSocket(4);
NodeOutput *outputSocket = this->getOutputSocket(0);
- bNode *editorsnode = getbNode();
- NodeHueSat *storage = (NodeHueSat *)editorsnode->storage;
ConvertRGBToHSVOperation *rgbToHSV = new ConvertRGBToHSVOperation();
converter.addOperation(rgbToHSV);
@@ -50,9 +51,9 @@ void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const
converter.addOperation(hsvToRGB);
ChangeHSVOperation *changeHSV = new ChangeHSVOperation();
- changeHSV->setHue(storage->hue);
- changeHSV->setSaturation(storage->sat);
- changeHSV->setValue(storage->val);
+ converter.mapInputSocket(hueSocket, changeHSV->getInputSocket(1));
+ converter.mapInputSocket(saturationSocket, changeHSV->getInputSocket(2));
+ converter.mapInputSocket(valueSocket, changeHSV->getInputSocket(3));
converter.addOperation(changeHSV);
MixBlendOperation *blend = new MixBlendOperation();
@@ -64,6 +65,6 @@ void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const
converter.addLink(changeHSV->getOutputSocket(), hsvToRGB->getInputSocket(0));
converter.addLink(hsvToRGB->getOutputSocket(), blend->getInputSocket(2));
converter.mapInputSocket(colorSocket, blend->getInputSocket(1));
- converter.mapInputSocket(valueSocket, blend->getInputSocket(0));
+ converter.mapInputSocket(facSocket, blend->getInputSocket(0));
converter.mapOutputSocket(outputSocket, blend->getOutputSocket());
}
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp b/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
index 964f1d64667..7ea974a41dc 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
@@ -25,6 +25,9 @@
ChangeHSVOperation::ChangeHSVOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR);
+ this->addInputSocket(COM_DT_VALUE);
+ this->addInputSocket(COM_DT_VALUE);
+ this->addInputSocket(COM_DT_VALUE);
this->addOutputSocket(COM_DT_COLOR);
this->m_inputOperation = NULL;
}
@@ -32,24 +35,34 @@ ChangeHSVOperation::ChangeHSVOperation() : NodeOperation()
void ChangeHSVOperation::initExecution()
{
this->m_inputOperation = getInputSocketReader(0);
+ this->m_hueOperation = getInputSocketReader(1);
+ this->m_saturationOperation = getInputSocketReader(2);
+ this->m_valueOperation = getInputSocketReader(3);
}
void ChangeHSVOperation::deinitExecution()
{
this->m_inputOperation = NULL;
+ this->m_hueOperation = NULL;
+ this->m_saturationOperation = NULL;
+ this->m_valueOperation = NULL;
}
void ChangeHSVOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float inputColor1[4];
+ float hue[4], saturation[4], value[4];
this->m_inputOperation->readSampled(inputColor1, x, y, sampler);
+ this->m_hueOperation->readSampled(hue, x, y, sampler);
+ this->m_saturationOperation->readSampled(saturation, x, y, sampler);
+ this->m_valueOperation->readSampled(value, x, y, sampler);
- output[0] = inputColor1[0] + (this->m_hue - 0.5f);
+ output[0] = inputColor1[0] + (hue[0] - 0.5f);
if (output[0] > 1.0f) output[0] -= 1.0f;
else if (output[0] < 0.0f) output[0] += 1.0f;
- output[1] = inputColor1[1] * this->m_saturation;
- output[2] = inputColor1[2] * this->m_value;
+ output[1] = inputColor1[1] * saturation[0];
+ output[2] = inputColor1[2] * value[0];
output[3] = inputColor1[3];
}
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.h b/source/blender/compositor/operations/COM_ChangeHSVOperation.h
index 76025e86b7a..800c09c05ff 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.h
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.h
@@ -32,10 +32,9 @@
class ChangeHSVOperation : public NodeOperation {
private:
SocketReader *m_inputOperation;
-
- float m_hue;
- float m_saturation;
- float m_value;
+ SocketReader *m_hueOperation;
+ SocketReader *m_saturationOperation;
+ SocketReader *m_valueOperation;
public:
/**
@@ -51,9 +50,5 @@ public:
*/
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
- void setHue(float hue) { this->m_hue = hue; }
- void setSaturation(float saturation) { this->m_saturation = saturation; }
- void setValue(float value) { this->m_value = value; }
-
};
#endif
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index e312c4e0dcb..6b7fb5246ca 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -121,7 +121,7 @@ struct BuilderWalkUserData {
static void modifier_walk(void *user_data,
struct Object * /*ob*/,
struct Object **obpoin,
- int /*cd_flag*/)
+ int /*cb_flag*/)
{
BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
if (*obpoin) {
@@ -320,6 +320,23 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
/* **** Build functions for entity nodes **** */
+void DepsgraphNodeBuilder::begin_build(Main *bmain) {
+ /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
+ * created or not. This flag is being set in add_id_node(), so functions
+ * shouldn't bother with setting it, they only might query this flag when
+ * needed.
+ */
+ BKE_main_id_tag_all(bmain, 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
+}
+
void DepsgraphNodeBuilder::build_group(Scene *scene,
Base *base,
Group *group)
@@ -626,18 +643,18 @@ void DepsgraphNodeBuilder::build_world(World *world)
}
/* world itself */
- IDDepsNode *world_node = add_id_node(world_id); /* world shading/params? */
+ add_id_node(world_id); /* world shading/params? */
build_animdata(world_id);
/* TODO: other settings? */
/* textures */
- build_texture_stack(world_node, world->mtex);
+ build_texture_stack(world->mtex);
/* world's nodetree */
if (world->nodetree) {
- build_nodetree(world_node, world->nodetree);
+ build_nodetree(world->nodetree);
}
}
@@ -807,13 +824,18 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
}
/* materials */
- for (int a = 1; a <= ob->totcol; a++) {
- Material *ma = give_current_material(ob, a);
- if (ma != NULL) {
- // XXX?!
- ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
- build_material(geom_node, ma);
+ if (ob->totcol != 0) {
+ for (int a = 1; a <= ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a);
+ if (ma != NULL) {
+ build_material(ma);
+ }
}
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_SHADING,
+ DEPSOP_TYPE_EXEC,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER, "Material Update");
}
/* geometry collision */
@@ -976,7 +998,7 @@ void DepsgraphNodeBuilder::build_lamp(Object *ob)
build_animdata(&la->id);
/* node for obdata */
- ComponentDepsNode *param_node = add_component_node(lamp_id, DEPSNODE_TYPE_PARAMETERS);
+ add_component_node(lamp_id, DEPSNODE_TYPE_PARAMETERS);
/* TODO(sergey): Is it really how we're supposed to work with drivers? */
add_operation_node(lamp_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
@@ -984,14 +1006,14 @@ void DepsgraphNodeBuilder::build_lamp(Object *ob)
/* lamp's nodetree */
if (la->nodetree) {
- build_nodetree(param_node, la->nodetree);
+ build_nodetree(la->nodetree);
}
/* textures */
- build_texture_stack(param_node, la->mtex);
+ build_texture_stack(la->mtex);
}
-void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree)
+void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
{
if (!ntree)
return;
@@ -1011,10 +1033,10 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
if (id != NULL) {
short id_type = GS(id->name);
if (id_type == ID_MA) {
- build_material(owner_node, (Material *)id);
+ build_material((Material *)id);
}
else if (id_type == ID_TE) {
- build_texture(owner_node, (Tex *)id);
+ build_texture((Tex *)id);
}
else if (id_type == ID_IM) {
build_image((Image *)id);
@@ -1022,7 +1044,7 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)id;
if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
- build_nodetree(owner_node, group_ntree);
+ build_nodetree(group_ntree);
}
}
}
@@ -1032,7 +1054,7 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
}
/* Recursively build graph for material */
-void DepsgraphNodeBuilder::build_material(DepsNode *owner_node, Material *ma)
+void DepsgraphNodeBuilder::build_material(Material *ma)
{
ID *ma_id = &ma->id;
if (ma_id->tag & LIB_TAG_DOIT) {
@@ -1050,14 +1072,14 @@ void DepsgraphNodeBuilder::build_material(DepsNode *owner_node, Material *ma)
build_animdata(ma_id);
/* textures */
- build_texture_stack(owner_node, ma->mtex);
+ build_texture_stack(ma->mtex);
/* material's nodetree */
- build_nodetree(owner_node, ma->nodetree);
+ build_nodetree(ma->nodetree);
}
/* Texture-stack attached to some shading datablock */
-void DepsgraphNodeBuilder::build_texture_stack(DepsNode *owner_node, MTex **texture_stack)
+void DepsgraphNodeBuilder::build_texture_stack(MTex **texture_stack)
{
int i;
@@ -1065,12 +1087,12 @@ void DepsgraphNodeBuilder::build_texture_stack(DepsNode *owner_node, MTex **text
for (i = 0; i < MAX_MTEX; i++) {
MTex *mtex = texture_stack[i];
if (mtex && mtex->tex)
- build_texture(owner_node, mtex->tex);
+ build_texture(mtex->tex);
}
}
/* Recursively build graph for texture */
-void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex)
+void DepsgraphNodeBuilder::build_texture(Tex *tex)
{
ID *tex_id = &tex->id;
if (tex_id->tag & LIB_TAG_DOIT) {
@@ -1080,7 +1102,7 @@ void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex)
/* Texture itself. */
build_animdata(tex_id);
/* Texture's nodetree. */
- build_nodetree(owner_node, tex->nodetree);
+ build_nodetree(tex->nodetree);
/* Special cases for different IDs which texture uses. */
if (tex->type == TEX_IMAGE) {
if (tex->ima != NULL) {
@@ -1114,8 +1136,8 @@ void DepsgraphNodeBuilder::build_compositor(Scene *scene)
//graph->get_node(&scene->id, NULL, DEPSNODE_TYPE_COMPOSITING, NULL);
/* for now, nodetrees are just parameters; compositing occurs in internals of renderer... */
- ComponentDepsNode *owner_node = add_component_node(&scene->id, DEPSNODE_TYPE_PARAMETERS);
- build_nodetree(owner_node, scene->nodetree);
+ add_component_node(&scene->id, DEPSNODE_TYPE_PARAMETERS);
+ build_nodetree(scene->nodetree);
}
void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 9cb8bc5d45c..c5035f35f6e 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -72,6 +72,8 @@ struct DepsgraphNodeBuilder {
DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
~DepsgraphNodeBuilder();
+ void begin_build(Main *bmain);
+
RootDepsNode *add_root_node();
IDDepsNode *add_id_node(ID *id);
TimeSourceDepsNode *add_time_source(ID *id);
@@ -147,10 +149,10 @@ struct DepsgraphNodeBuilder {
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_nodetree(bNodeTree *ntree);
+ void build_material(Material *ma);
+ void build_texture(Tex *tex);
+ void build_texture_stack(MTex **texture_stack);
void build_image(Image *image);
void build_world(World *world);
void build_compositor(Scene *scene);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index 4a5f3dc8664..f2437ce1fac 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -119,7 +119,17 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
* Eventually, we need some type of proxy/isolation mechanism in-between here
* to ensure that we can use same rig multiple times in same scene...
*/
- build_animdata(&arm->id);
+ if ((arm->id.tag & LIB_TAG_DOIT) == 0) {
+ build_animdata(&arm->id);
+
+ /* Make sure pose is up-to-date with armature updates. */
+ add_operation_node(&arm->id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_EXEC,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Armature Eval");
+ }
/* Rebuild pose if not up to date. */
if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
@@ -141,14 +151,6 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
}
}
- /* Make sure pose is up-to-date with armature updates. */
- add_operation_node(&arm->id,
- DEPSNODE_TYPE_PARAMETERS,
- DEPSOP_TYPE_EXEC,
- NULL,
- DEG_OPCODE_PLACEHOLDER,
- "Armature Eval");
-
/**
* Pose Rig Graph
* ==============
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
index bcd4bc51448..99e61692231 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
@@ -65,20 +65,6 @@ namespace DEG {
void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
{
- /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
- * created or not. This flag is being set in add_id_node(), so functions
- * shouldn't bother with setting it, they only might query this flag when
- * needed.
- */
- BKE_main_id_tag_all(bmain, 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
-
/* scene ID block */
add_id_node(&scene->id);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index b5272d3acf2..94cff521edc 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -129,8 +129,8 @@ static bool python_driver_depends_on_time(ChannelDriver *driver)
/* Function calls are considered dependent on a time. */
return true;
}
- if (strstr(driver->expression, "time") != NULL) {
- /* Variable `time` depends on time. */
+ if (strstr(driver->expression, "frame") != NULL) {
+ /* Variable `frame` depends on time. */
/* TODO(sergey): This is a bit weak, but not sure about better way of
* handling this.
*/
@@ -339,6 +339,22 @@ void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key,
/* **** Functions to build relations between entities **** */
+void DepsgraphRelationBuilder::begin_build(Main *bmain)
+{
+ /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
+ * created or not.
+ */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ /* XXX nested node trees are notr 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
+}
+
void DepsgraphRelationBuilder::build_group(Main *bmain,
Scene *scene,
Object *object,
@@ -489,7 +505,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
/* grease pencil */
if (ob->gpd) {
- build_gpencil(&ob->id, ob->gpd);
+ build_gpencil(ob->gpd);
}
}
@@ -1062,10 +1078,10 @@ void DepsgraphRelationBuilder::build_world(World *world)
/* TODO: other settings? */
/* textures */
- build_texture_stack(world_id, world->mtex);
+ build_texture_stack(world->mtex);
/* world's nodetree */
- build_nodetree(world_id, world->nodetree);
+ build_nodetree(world->nodetree);
}
void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
@@ -1402,14 +1418,19 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
}
/* materials */
- if (ob->totcol) {
- int a;
-
- for (a = 1; a <= ob->totcol; a++) {
+ if (ob->totcol != 0) {
+ ComponentKey object_shading_key(&ob->id, DEPSNODE_TYPE_SHADING);
+ for (int a = 1; a <= ob->totcol; a++) {
Material *ma = give_current_material(ob, a);
-
- if (ma)
- build_material(&ob->id, ma);
+ if (ma != NULL) {
+ build_material(ma);
+ ComponentKey material_shading_key(&ma->id,
+ DEPSNODE_TYPE_SHADING);
+ add_relation(material_shading_key,
+ object_shading_key,
+ DEPSREL_TYPE_UPDATE,
+ "Object Shading");
+ }
}
}
@@ -1568,17 +1589,17 @@ void DepsgraphRelationBuilder::build_lamp(Object *ob)
/* lamp's nodetree */
if (la->nodetree) {
- build_nodetree(lamp_id, la->nodetree);
+ build_nodetree(la->nodetree);
ComponentKey nodetree_key(&la->nodetree->id, DEPSNODE_TYPE_PARAMETERS);
add_relation(nodetree_key, parameters_key,
DEPSREL_TYPE_COMPONENT_ORDER, "NTree->Lamp Parameters");
}
/* textures */
- build_texture_stack(lamp_id, la->mtex);
+ build_texture_stack(la->mtex);
}
-void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
+void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
{
if (!ntree)
return;
@@ -1596,15 +1617,15 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
if (bnode->id) {
if (GS(bnode->id->name) == ID_MA) {
- build_material(owner, (Material *)bnode->id);
+ build_material((Material *)bnode->id);
}
else if (bnode->type == ID_TE) {
- build_texture(owner, (Tex *)bnode->id);
+ build_texture((Tex *)bnode->id);
}
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)bnode->id;
if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
- build_nodetree(owner, group_ntree);
+ build_nodetree(group_ntree);
group_ntree->id.tag |= LIB_TAG_DOIT;
}
OperationKey group_parameters_key(&group_ntree->id,
@@ -1622,12 +1643,10 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
add_relation(animation_key, parameters_key,
DEPSREL_TYPE_COMPONENT_ORDER, "NTree Parameters");
}
-
- // TODO: link from nodetree to owner_component?
}
/* Recursively build graph for material */
-void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
+void DepsgraphRelationBuilder::build_material(Material *ma)
{
ID *ma_id = &ma->id;
if (ma_id->tag & LIB_TAG_DOIT) {
@@ -1639,14 +1658,26 @@ void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
build_animdata(ma_id);
/* textures */
- build_texture_stack(owner, ma->mtex);
+ build_texture_stack(ma->mtex);
/* material's nodetree */
- build_nodetree(owner, ma->nodetree);
+ if (ma->nodetree != NULL) {
+ build_nodetree(ma->nodetree);
+ OperationKey ntree_key(&ma->nodetree->id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "Parameters Eval");
+ OperationKey material_key(&ma->id,
+ DEPSNODE_TYPE_SHADING,
+ DEG_OPCODE_PLACEHOLDER,
+ "Material Update");
+ add_relation(ntree_key, material_key,
+ DEPSREL_TYPE_UPDATE, "Material's NTree");
+ }
}
/* Recursively build graph for texture */
-void DepsgraphRelationBuilder::build_texture(ID *owner, Tex *tex)
+void DepsgraphRelationBuilder::build_texture(Tex *tex)
{
ID *tex_id = &tex->id;
if (tex_id->tag & LIB_TAG_DOIT) {
@@ -1658,11 +1689,11 @@ void DepsgraphRelationBuilder::build_texture(ID *owner, Tex *tex)
build_animdata(tex_id);
/* texture's nodetree */
- build_nodetree(owner, tex->nodetree);
+ build_nodetree(tex->nodetree);
}
/* Texture-stack attached to some shading datablock */
-void DepsgraphRelationBuilder::build_texture_stack(ID *owner, MTex **texture_stack)
+void DepsgraphRelationBuilder::build_texture_stack(MTex **texture_stack)
{
int i;
@@ -1670,17 +1701,17 @@ void DepsgraphRelationBuilder::build_texture_stack(ID *owner, MTex **texture_sta
for (i = 0; i < MAX_MTEX; i++) {
MTex *mtex = texture_stack[i];
if (mtex && mtex->tex)
- build_texture(owner, mtex->tex);
+ build_texture(mtex->tex);
}
}
void DepsgraphRelationBuilder::build_compositor(Scene *scene)
{
/* For now, just a plain wrapper? */
- build_nodetree(&scene->id, scene->nodetree);
+ build_nodetree(scene->nodetree);
}
-void DepsgraphRelationBuilder::build_gpencil(ID *UNUSED(owner), bGPdata *gpd)
+void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd)
{
/* animation */
build_animdata(&gpd->id);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 6e8485bee30..054e4103290 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -171,6 +171,8 @@ struct DepsgraphRelationBuilder
{
DepsgraphRelationBuilder(Depsgraph *graph);
+ void begin_build(Main *bmain);
+
template <typename KeyFrom, typename KeyTo>
void add_relation(const KeyFrom& key_from,
const KeyTo& key_to,
@@ -217,12 +219,12 @@ struct DepsgraphRelationBuilder
void build_obdata_geom(Main *bmain, Scene *scene, Object *ob);
void build_camera(Object *ob);
void build_lamp(Object *ob);
- void build_nodetree(ID *owner, bNodeTree *ntree);
- void build_material(ID *owner, Material *ma);
- void build_texture(ID *owner, Tex *tex);
- void build_texture_stack(ID *owner, MTex **texture_stack);
+ void build_nodetree(bNodeTree *ntree);
+ void build_material(Material *ma);
+ void build_texture(Tex *tex);
+ void build_texture_stack(MTex **texture_stack);
void build_compositor(Scene *scene);
- void build_gpencil(ID *owner, bGPdata *gpd);
+ void build_gpencil(bGPdata *gpd);
void build_cachefile(CacheFile *cache_file);
void build_mask(Mask *mask);
void build_movieclip(MovieClip *clip);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
index 6b51a957da0..8a3476cff45 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
@@ -69,20 +69,8 @@ namespace DEG {
void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
{
- /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
- * 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...
+ build_scene(bmain, scene->set);
}
/* scene objects */
@@ -132,7 +120,7 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
/* grease pencil */
if (scene->gpd) {
- build_gpencil(&scene->id, scene->gpd);
+ build_gpencil(scene->gpd);
}
/* Masks. */
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 9952f714145..3a69469053c 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -209,6 +209,7 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
* - this way it should be the first in the graph,
* reflecting its role as the entrypoint
*/
+ node_builder.begin_build(bmain);
node_builder.add_root_node();
node_builder.build_scene(bmain, scene);
@@ -221,6 +222,7 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
* it doesnt add any operations anyway and is not clear what part of the
* scene is to be connected.
*/
+ relation_builder.begin_build(bmain);
#if 0
relation_builder.add_relation(RootKey(),
IDKey(scene),
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 4ce91516c84..39c189629f2 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -145,7 +145,7 @@ DepsOperationStringifier::DepsOperationStringifier()
const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode)
{
- BLI_assert((opcode > 0) && (opcode < DEG_NUM_OPCODES));
+ BLI_assert((opcode >= 0) && (opcode < DEG_NUM_OPCODES));
if (opcode >= 0 && opcode < DEG_NUM_OPCODES) {
return names_[opcode];
}
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index c12a050e9ba..2f73eb6b71c 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -2223,7 +2223,7 @@ typedef struct tAnimFilterModifiersContext {
/* dependency walker callback for modifier dependencies */
-static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cd_flag))
+static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cb_flag))
{
tAnimFilterModifiersContext *afm = (tAnimFilterModifiersContext *)afm_ptr;
ID *owner_id = &ob->id;
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 1703210f0b6..c1e82583521 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
@@ -668,7 +669,7 @@ static void flip_names(tAnimCopybufItem *aci, char **name)
/* more ninja stuff, temporary substitute with NULL terminator */
str_start[length] = 0;
- BKE_deform_flip_side_name(bname_new, str_start, false);
+ BLI_string_flip_side_name(bname_new, str_start, false, sizeof(bname_new));
str_start[length] = '\"';
str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path");
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 6228874343b..bbc81f522fa 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_ghash.h"
+#include "BLI_string_utils.h"
#include "BKE_action.h"
#include "BKE_constraint.h"
@@ -619,9 +620,9 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
if (EBONE_VISIBLE(arm, ebone_iter) &&
(ebone_iter->flag & BONE_SELECTED))
{
- char name_flip[MAX_VGROUP_NAME];
+ char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+ BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
if (STREQ(name_flip, ebone_iter->name)) {
/* if the name matches, we don't have the potential to be mirrored, just skip */
@@ -679,9 +680,9 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
/* will be set if the mirror bone already exists (no need to make a new one) */
(ebone_iter->temp.ebone == NULL))
{
- char name_flip[MAX_VGROUP_NAME];
+ char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+ BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
/* bones must have a side-suffix */
if (!STREQ(name_flip, ebone_iter->name)) {
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 56dbdb3a639..fa192ed6f36 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -37,6 +37,8 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -297,6 +299,55 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
}
}
+typedef struct BoneFlipNameData {
+ struct BoneFlipNameData *next, *prev;
+ char *name;
+ char name_flip[MAXBONENAME];
+} BoneFlipNameData;
+
+/**
+ * Renames (by flipping) all selected bones at once.
+ *
+ * This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time
+ * all the bones are safely renamed, without conflicting with each other.
+ *
+ * \param arm Armature the bones belong to
+ * \param bones ListBase of BoneConflict elems, populated via ED_armature_bones_flip_names_add
+ */
+void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names)
+{
+ ListBase bones_names_conflicts = {NULL};
+ BoneFlipNameData *bfn;
+
+ /* First pass: generate flip names, and blindly rename.
+ * If rename did not yield expected result, store both bone's name and expected flipped one into temp list
+ * for second pass. */
+ for (LinkData *link = bones_names->first; link; link = link->next) {
+ char name_flip[MAXBONENAME];
+ char *name = link->data;
+
+ /* Do not strip numbers, otherwise we'll end up with completely mismatched names in cases like
+ * Bone.R, Bone.R.001, Bone.R.002, etc. */
+ BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
+
+ ED_armature_bone_rename(arm, name, name_flip);
+
+ if (!STREQ(name, name_flip)) {
+ bfn = alloca(sizeof(BoneFlipNameData));
+ bfn->name = name;
+ BLI_strncpy(bfn->name_flip, name_flip, sizeof(bfn->name_flip));
+ BLI_addtail(&bones_names_conflicts, bfn);
+ }
+ }
+
+ /* Second pass to handle the bones that have naming conflicts with other bones.
+ * Note that if the other bone was not selected, its name was not flipped, so conflict remains and that second
+ * rename simply generates a new numbered alternative name. */
+ for (bfn = bones_names_conflicts.first; bfn; bfn = bfn->next) {
+ ED_armature_bone_rename(arm, bfn->name, bfn->name_flip);
+ }
+}
+
/* ************************************************** */
/* Bone Renaming - EditMode */
@@ -304,20 +355,24 @@ static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_edit_object(C);
bArmature *arm;
-
+
/* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
+ if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
+
arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
+
+ ListBase bones_names= {NULL};
+
CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
{
- char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, ebone->name, true);
- ED_armature_bone_rename(arm, ebone->name, name_flip);
+ BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
}
CTX_DATA_END;
+
+ ED_armature_bones_flip_names(arm, &bones_names);
+
+ BLI_freelistN(&bones_names);
/* since we renamed stuff... */
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 5a70a45fad4..e9946abba0b 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -35,9 +35,10 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_context.h"
-#include "BKE_deform.h"
+//#include "BKE_deform.h"
#include "BKE_report.h"
#include "BIF_gl.h"
@@ -817,10 +818,10 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
{
EditBone *ebone;
- char body_tmp[MAX_VGROUP_NAME];
- char prefix_act[MAX_VGROUP_NAME];
+ char body_tmp[MAXBONENAME];
+ char prefix_act[MAXBONENAME];
- BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp);
+ BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name));
if (prefix_act[0] == '\0')
return;
@@ -828,8 +829,8 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
/* Find matches */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (EBONE_SELECTABLE(arm, ebone)) {
- char prefix_other[MAX_VGROUP_NAME];
- BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp);
+ char prefix_other[MAXBONENAME];
+ BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
if (STREQ(prefix_act, prefix_other)) {
ED_armature_ebone_select_set(ebone, true);
}
@@ -841,10 +842,10 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
{
EditBone *ebone;
- char body_tmp[MAX_VGROUP_NAME];
- char suffix_act[MAX_VGROUP_NAME];
+ char body_tmp[MAXBONENAME];
+ char suffix_act[MAXBONENAME];
- BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act);
+ BLI_string_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name));
if (suffix_act[0] == '\0')
return;
@@ -852,8 +853,8 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
/* Find matches */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (EBONE_SELECTABLE(arm, ebone)) {
- char suffix_other[MAX_VGROUP_NAME];
- BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other);
+ char suffix_other[MAXBONENAME];
+ BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
if (STREQ(suffix_act, suffix_other)) {
ED_armature_ebone_select_set(ebone, true);
}
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 28fddbab796..e8d41f722d7 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -360,7 +361,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
if (dgroup && mirror) {
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, dgroup->name, false);
+ BLI_string_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip));
dgroupflip[j] = defgroup_find_name(ob, name_flip);
}
}
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 6979a324b69..a3b439536b7 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -34,6 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_armature.h"
#include "BKE_context.h"
@@ -262,7 +263,7 @@ EditBone *ED_armature_bone_get_mirrored(const ListBase *edbo, EditBone *ebo)
if (ebo == NULL)
return NULL;
- BKE_deform_flip_side_name(name_flip, ebo->name, false);
+ BLI_string_flip_side_name(name_flip, ebo->name, false, sizeof(name_flip));
if (!STREQ(name_flip, ebo->name)) {
return ED_armature_bone_find_name(edbo, name_flip);
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 322476dcca0..86b7271bfff 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -593,20 +593,24 @@ static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm;
-
+
/* paranoia checks */
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
+
arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
+
+ ListBase bones_names = {NULL};
+
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
{
- char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, pchan->name, true);
- ED_armature_bone_rename(arm, pchan->name, name_flip);
+ BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name));
}
CTX_DATA_END;
+
+ ED_armature_bones_flip_names(arm, &bones_names);
+
+ BLI_freelistN(&bones_names);
/* since we renamed stuff... */
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 9309592bb46..e3c64b523b1 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -34,6 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index b645f1fb2f3..063ba37f20d 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -36,6 +36,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
@@ -286,7 +287,7 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
/* get the name - if flipping, we must flip this first */
if (flip)
- BKE_deform_flip_side_name(name, chan->name, false);
+ BLI_string_flip_side_name(name, chan->name, false, sizeof(name));
else
BLI_strncpy(name, chan->name, sizeof(name));
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 6604d595573..3d5317b2ebd 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -44,6 +44,7 @@ set(SRC
gpencil_convert.c
gpencil_data.c
gpencil_edit.c
+ gpencil_interpolate.c
gpencil_ops.c
gpencil_paint.c
gpencil_select.c
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 2fd574d6523..a542bf8fa11 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -1563,7 +1563,7 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
{
bGPdata *gpd_source = NULL;
ToolSettings *ts;
- bGPDbrush *brush;
+ bGPDbrush *brush = NULL;
if (scene) {
ts = scene->toolsettings;
brush = BKE_gpencil_brush_getactive(ts);
@@ -1572,8 +1572,7 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
BKE_gpencil_brush_init_presets(ts);
brush = BKE_gpencil_brush_getactive(ts);
}
- }
- if (scene) {
+
if (spacetype == SPACE_VIEW3D) {
gpd_source = (scene->gpd ? scene->gpd : NULL);
}
@@ -1581,13 +1580,12 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
/* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */
gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
}
-
+
if (gpd_source) {
if (brush != NULL) {
gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source,
offsx, offsy, winx, winy, cfra, dflag);
}
-
}
}
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index ae83e899649..6980ad46241 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -42,6 +42,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 15f65b394a9..5b011b679a6 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -682,6 +682,87 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
}
+/* ********************* Add Blank Frame *************************** */
+
+/* Basically the same as the drawing op */
+static int UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C)
+{
+ if (ED_operator_regionactive(C)) {
+ /* check if current context can support GPencil data */
+ if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
+ return 1;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ }
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ }
+
+ return 0;
+}
+
+static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd);
+
+ const bool all_layers = RNA_boolean_get(op->ptr, "all_layers");
+
+ /* Initialise datablock and an active layer if nothing exists yet */
+ if (ELEM(NULL, gpd, active_gpl)) {
+ /* let's just be lazy, and call the "Add New Layer" operator, which sets everything up as required */
+ WM_operator_name_call(C, "GPENCIL_OT_layer_add", WM_OP_EXEC_DEFAULT, NULL);
+ }
+
+ /* Go through each layer, adding a frame after the active one
+ * and/or shunting all the others out of the way
+ */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ if ((all_layers == false) && (gpl != active_gpl)) {
+ continue;
+ }
+
+ /* 1) Check for an existing frame on the current frame */
+ bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, CFRA);
+ if (gpf) {
+ /* Shunt all frames after (and including) the existing one later by 1-frame */
+ for (; gpf; gpf = gpf->next) {
+ gpf->framenum += 1;
+ }
+ }
+
+ /* 2) Now add a new frame, with nothing in it */
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_blank_frame_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Blank Frame";
+ ot->idname = "GPENCIL_OT_blank_frame_add";
+ ot->description = "Add a new frame with nothing in it on the current frame. "
+ "If there is already a frame, all existing frames are shifted one frame later";
+
+ /* callbacks */
+ ot->exec = gp_blank_frame_add_exec;
+ ot->poll = gp_add_poll;
+
+ /* properties */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_boolean(ot->srna, "all_layers", false, "All Layers", "Create blank frame in all layers, not only active");
+}
+
/* ******************* Delete Active Frame ************************ */
static int gp_actframe_delete_poll(bContext *C)
@@ -1897,6 +1978,13 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
/* ***************** Reproject Strokes ********************** */
+typedef enum eGP_ReprojectModes {
+ /* On same plane, parallel to viewplane */
+ GP_REPROJECT_PLANAR = 0,
+ /* Reprojected on to the scene geometry */
+ GP_REPROJECT_SURFACE,
+} eGP_ReprojectModes;
+
static int gp_strokes_reproject_poll(bContext *C)
{
/* 2 Requirements:
@@ -1906,14 +1994,23 @@ static int gp_strokes_reproject_poll(bContext *C)
return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C));
}
-static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op))
+static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
GP_SpaceConversion gsc = {NULL};
+ eGP_ReprojectModes mode = RNA_boolean_get(op->ptr, "type");
/* init space conversion stuff */
gp_point_conversion_init(C, &gsc);
+ /* init autodist for geometry projection */
+ if (mode == GP_REPROJECT_SURFACE) {
+ view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar);
+ ED_view3d_autodist_init(scene, gsc.ar, CTX_wm_view3d(C), 0);
+ }
+
+ // TODO: For deforming geometry workflow, create new frames?
+
/* Go through each editable + selected stroke, adjusting each of its points one by one... */
GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
@@ -1949,7 +2046,27 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op))
/* 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);
+ if (mode == GP_REPROJECT_PLANAR) {
+ /* Planar - All on same plane parallel to the viewplane */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+ }
+ else {
+ /* Geometry - Snap to surfaces of visible geometry */
+ /* XXX: There will be precision loss (possible stairstep artifacts) from this conversion to satisfy the API's */
+ const int screen_co[2] = {(int)xy[0], (int)xy[1]};
+
+ int depth_margin = 0; // XXX: 4 for strokes, 0 for normal
+ float depth;
+
+ /* XXX: The proper procedure computes the depths into an array, to have smooth transitions when all else fails... */
+ if (ED_view3d_autodist_depth(gsc.ar, screen_co, depth_margin, &depth)) {
+ ED_view3d_autodist_simple(gsc.ar, screen_co, &pt->x, 0, &depth);
+ }
+ else {
+ /* Default to planar */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+ }
+ }
/* Unapply parent corrections */
if (gpl->parent) {
@@ -1966,21 +2083,36 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op))
void GPENCIL_OT_reproject(wmOperatorType *ot)
{
+ static EnumPropertyItem reproject_type[] = {
+ {GP_REPROJECT_PLANAR, "PLANAR", 0, "Planar",
+ "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint "
+ "using 'Cursor' Stroke Placement"},
+ {GP_REPROJECT_SURFACE, "SURFACE", 0, "Surface",
+ "Reproject the strokes on to the scene geometry, as if drawn using 'Surface' placement"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* 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)";
+ ot->description = "Reproject the selected strokes from the current viewpoint as if they had been newly drawn "
+ "(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, "
+ "or for matching deforming geometry)";
/* callbacks */
+ ot->invoke = WM_menu_invoke;
ot->exec = gp_strokes_reproject_exec;
ot->poll = gp_strokes_reproject_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", reproject_type, GP_REPROJECT_PLANAR, "Projection Type", "");
}
/* ******************* Stroke subdivide ************************** */
+
/* helper: Count how many points need to be inserted */
static int gp_count_subdivision_cuts(bGPDstroke *gps)
{
@@ -2098,673 +2230,3 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
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 e2e5fc28710..5c7c9b84adb 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -287,6 +287,8 @@ 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_blank_frame_add(struct wmOperatorType *ot);
+
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
@@ -340,6 +342,7 @@ void gpencil_undo_finish(void);
void GPENCIL_OT_interpolate(struct wmOperatorType *ot);
void GPENCIL_OT_interpolate_sequence(struct wmOperatorType *ot);
+void GPENCIL_OT_interpolate_reverse(struct wmOperatorType *ot);
/* ****************************************************** */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
new file mode 100644
index 00000000000..297058168a0
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -0,0 +1,1145 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for interpolating new Grease Pencil frames from existing strokes
+ */
+
+/** \file blender/editors/gpencil/gpencil_interpolate.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_easing.h"
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_color_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "gpencil_intern.h"
+
+/* ************************************************ */
+/* Core/Shared Utilities */
+
+/* Poll callback for interpolation operators */
+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;
+}
+
+/* Perform 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);
+ }
+}
+
+/* ****************** Interpolate Interactive *********************** */
+
+/* Helper: Update all strokes interpolated */
+static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
+{
+ tGPDinterpolate_layer *tgpil;
+ const float shift = tgpi->shift;
+
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ bGPDstroke *new_stroke;
+ const float factor = tgpil->factor + shift;
+
+ for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) {
+ bGPDstroke *gps_from, *gps_to;
+ int stroke_idx;
+
+ if (new_stroke->totpoints == 0) {
+ continue;
+ }
+
+ /* get strokes to interpolate */
+ stroke_idx = BLI_findindex(&tgpil->interFrame->strokes, new_stroke);
+
+ gps_from = BLI_findlink(&tgpil->prevFrame->strokes, stroke_idx);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, stroke_idx);
+
+ /* 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);
+ eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag;
+
+ /* get layers */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* all layers or only active */
+ if (!(flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* read strokes */
+ for (bGPDstroke *gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) {
+ bGPDstroke *gps_to;
+ int fFrame;
+
+ /* only selected */
+ if ((flag & GP_TOOLFLAG_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 true;
+ }
+ }
+ return false;
+}
+
+/* Helper: Create internal strokes interpolated */
+static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
+{
+ bGPdata *gpd = tgpi->gpd;
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDframe *actframe = active_gpl->actframe;
+
+ /* save initial factor for active layer to define shift limits */
+ tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - 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 (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ tGPDinterpolate_layer *tgpil;
+
+ /* all layers or only active */
+ if (!(tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && (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 = 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 (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
+ bGPDstroke *gps_to;
+ int fFrame;
+
+ bGPDstroke *new_stroke;
+ bool valid = true;
+
+
+ /* only selected */
+ if ((tgpi->flag & GP_TOOLFLAG_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);
+ }
+ }
+}
+
+/* ----------------------- */
+/* Drawing Callbacks */
+
+/* Drawing callback for modal operator in screen mode */
+static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
+ ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL);
+}
+
+/* Drawing callback for modal operator in 3d mode */
+static void gpencil_interpolate_draw_3d(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
+ ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW);
+}
+
+/* ----------------------- */
+
+/* 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);
+}
+
+/* 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);
+}
+
+/* ----------------------- */
+
+/* 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;
+}
+
+/* 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_interpolate.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;
+}
+
+/* Allocate memory and initialize values */
+static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *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;
+}
+
+/* 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;
+}
+
+/* ----------------------- */
+
+/* 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);
+ bGPDframe *actframe = gpl->actframe;
+ tGPDinterpolate *tgpi = NULL;
+
+ /* cannot interpolate if not between 2 frames */
+ if (ELEM(NULL, actframe, actframe->next)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* cannot interpolate in extremes */
+ if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* need editable strokes */
+ if (!gp_interpolate_check_todo(C, gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable strokes");
+ 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 strokes can 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, tgpi, REGION_DRAW_POST_PIXEL);
+ tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, 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)) {
+ const float factor = tgpi->init_factor;
+ float value;
+
+ /* 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;
+}
+
+/* Cancel handler */
+static void gpencil_interpolate_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_interpolate_exit(C, op);
+}
+
+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";
+
+ /* 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;
+
+ /* properties */
+ RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Bias factor for which frame has more influence on the interpolated strokes", -0.9f, 0.9f);
+}
+
+/* ****************** Interpolate Sequence *********************** */
+
+/* Helper: Perform easing equation calculations for GP interpolation operator */
+static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_settings, float time)
+{
+ const float begin = 0.0f;
+ const float change = 1.0f;
+ const float duration = 1.0f;
+
+ const float back = ipo_settings->back;
+ const float amplitude = ipo_settings->amplitude;
+ const float period = ipo_settings->period;
+
+ eBezTriple_Easing easing = ipo_settings->easing;
+ float result = time;
+
+ switch (ipo_settings->type) {
+ case GP_IPO_BACK:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_back_ease_in(time, begin, change, duration, back);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_back_ease_out(time, begin, change, duration, back);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_back_ease_in_out(time, begin, change, duration, back);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_back_ease_out(time, begin, change, duration, back);
+ break;
+ }
+ break;
+
+ case GP_IPO_BOUNCE:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_bounce_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_bounce_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_bounce_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_bounce_ease_out(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_CIRC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_circ_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_circ_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_circ_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_circ_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_CUBIC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_cubic_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_cubic_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_cubic_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_cubic_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_ELASTIC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
+ break;
+ }
+ break;
+
+ case GP_IPO_EXPO:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_expo_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_expo_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_expo_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_expo_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUAD:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quad_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quad_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quad_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quad_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUART:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quart_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quart_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quart_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quart_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUINT:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quint_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quint_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quint_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quint_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_SINE:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_sine_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_sine_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_sine_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_sine_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ default:
+ printf("%s: Unknown interpolation type - %d\n", __func__, ipo_settings->type);
+ break;
+ }
+
+ return result;
+}
+
+static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDframe *actframe = active_gpl->actframe;
+
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate;
+ eGP_Interpolate_SettingsFlag flag = ipo_settings->flag;
+
+ /* cannot interpolate if not between 2 frames */
+ if (ELEM(NULL, actframe, actframe->next)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer");
+ return OPERATOR_CANCELLED;
+ }
+ /* cannot interpolate in extremes */
+ if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* loop all layer to check if need interpolation */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *prevFrame, *nextFrame;
+ bGPDstroke *gps_from, *gps_to;
+ int cframe, fFrame;
+
+ /* all layers or only active */
+ if (((flag & GP_TOOLFLAG_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++) {
+ bGPDframe *interFrame = NULL;
+ float factor;
+
+ /* get interpolation factor */
+ factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1);
+
+ if (ipo_settings->type == GP_IPO_CURVEMAP) {
+ /* custom curvemap */
+ if (ipo_settings->custom_ipo) {
+ factor = curvemapping_evaluateF(ipo_settings->custom_ipo, 0, factor);
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Custom interpolation curve does not exist");
+ }
+ }
+ else if (ipo_settings->type >= GP_IPO_BACK) {
+ /* easing equation... */
+ factor = gp_interpolate_seq_easing_calc(ipo_settings, factor);
+ }
+
+ /* create new strokes data with interpolated points reading original stroke */
+ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
+ bGPDstroke *new_stroke;
+
+ /* only selected */
+ if ((flag & GP_TOOLFLAG_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;
+}
+
+void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Interpolate Sequence";
+ ot->idname = "GPENCIL_OT_interpolate_sequence";
+ ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames";
+
+ /* api callbacks */
+ ot->exec = gpencil_interpolate_seq_exec;
+ ot->poll = gpencil_interpolate_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************** Remove Breakdowns ************************ */
+
+/* Same as gpencil_interpolate_poll(),
+ * except we ALSO need to have an active frame that is a breakdown
+ */
+static int gpencil_interpolate_reverse_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;
+ }
+
+ /* need to be on a breakdown frame */
+ if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) {
+ CTX_wm_operator_poll_msg_set(C, "Expected current frame to be a breakdown");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ /* Go through each layer, deleting the breakdowns around the current frame,
+ * but only if there is a keyframe nearby to stop at
+ */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *start_key = NULL;
+ bGPDframe *end_key = NULL;
+ bGPDframe *gpf, *gpfn;
+
+ /* Only continue if we're currently on a breakdown keyframe */
+ if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN))
+ continue;
+
+ /* Search left for "start_key" (i.e. the first breakdown to remove) */
+ gpf = gpl->actframe;
+ while (gpf) {
+ if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
+ /* A breakdown... keep going left */
+ start_key = gpf;
+ gpf = gpf->prev;
+ }
+ else {
+ /* Not a breakdown (may be a key, or an extreme, or something else that wasn't generated)... stop */
+ break;
+ }
+ }
+
+ /* Search right for "end_key" (i.e. the last breakdown to remove) */
+ gpf = gpl->actframe;
+ while (gpf) {
+ if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
+ /* A breakdown... keep going right */
+ end_key = gpf;
+ gpf = gpf->next;
+ }
+ else {
+ /* Not a breakdown... stop */
+ break;
+ }
+ }
+
+ /* Did we find anything? */
+ /* NOTE: We should only proceed if there's something before/after these extents...
+ * Otherwise, there's just an extent of breakdowns with no keys to interpolate between
+ */
+ if ((start_key && end_key) &&
+ ELEM(NULL, start_key->prev, end_key->next) == false)
+ {
+ /* Set actframe to the key before start_key, since the keys have been removed now */
+ gpl->actframe = start_key->prev;
+
+ /* Free each frame we're removing (except the last one) */
+ for (gpf = start_key; gpf && gpf != end_key; gpf = gpfn) {
+ gpfn = gpf->next;
+
+ /* free strokes and their associated memory */
+ BKE_gpencil_free_strokes(gpf);
+ BLI_freelinkN(&gpl->frames, gpf);
+ }
+
+ /* Now free the last one... */
+ BKE_gpencil_free_strokes(end_key);
+ BLI_freelinkN(&gpl->frames, end_key);
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_interpolate_reverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Breakdowns";
+ ot->idname = "GPENCIL_OT_interpolate_reverse";
+ ot->description = "Remove breakdown frames generated by interpolating between two Grease Pencil frames";
+
+ /* callbacks */
+ ot->exec = gpencil_interpolate_reverse_exec;
+ ot->poll = gpencil_interpolate_reverse_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* *************************************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 057d53ea458..78e1a0dda36 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -102,6 +102,10 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
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);
+ /* Add Blank Frame */
+ /* XXX: BKEY or NKEY? BKEY is easier to reach from DKEY, so we'll use that for now */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_blank_frame_add", BKEY, 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);
@@ -401,6 +405,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_isolate);
WM_operatortype_append(GPENCIL_OT_layer_merge);
+ WM_operatortype_append(GPENCIL_OT_blank_frame_add);
+
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
@@ -443,6 +449,7 @@ void ED_operatortypes_gpencil(void)
/* Interpolation */
WM_operatortype_append(GPENCIL_OT_interpolate);
WM_operatortype_append(GPENCIL_OT_interpolate_sequence);
+ WM_operatortype_append(GPENCIL_OT_interpolate_reverse);
}
void ED_operatormacros_gpencil(void)
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index c23bfb1ff60..5879306b06c 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1623,16 +1623,24 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
* 2) Ensure that p->gpf refers to the frame used for the active layer
* (to avoid problems with other tools which expect it to exist)
*/
- bGPDlayer *gpl;
- for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
+ bool has_layer_to_erase = false;
+
+ for (bGPDlayer *gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
/* Skip if layer not editable */
if (gpencil_layer_is_editable(gpl) == false)
continue;
/* Add a new frame if needed (and based off the active frame,
* as we need some existing strokes to erase)
+ *
+ * Note: We don't add a new frame if there's nothing there now, so
+ * -> If there are no frames at all, don't add one
+ * -> If there are no strokes in that frame, don't add a new empty frame
*/
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ if (gpl->actframe && gpl->actframe->strokes.first) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ has_layer_to_erase = true;
+ }
/* XXX: we omit GP_FRAME_PAINT here for now,
* as it is only really useful for doing
@@ -1652,10 +1660,10 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
}
}
- if (p->gpf == NULL) {
+ if (has_layer_to_erase == false) {
p->status = GP_STATUS_ERROR;
//if (G.debug & G_DEBUG)
- printf("Error: No frame created (gpencil_paint_init)\n");
+ printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
return;
}
}
@@ -2432,6 +2440,14 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* enable continuous if release D key in mid drawing */
p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON;
}
+ else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
+ /* Add Blank Frame
+ * - Since this operator is non-modal, we can just call it here, and keep going...
+ * - This operator is especially useful when animating
+ */
+ WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
+ estate = OPERATOR_RUNNING_MODAL;
+ }
else {
estate = OPERATOR_RUNNING_MODAL;
}
@@ -2594,7 +2610,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else if (p->status != GP_STATUS_ERROR) {
/* User clicked outside bounds of window while idling, so exit paintmode
- * NOTE: Don't eter this case if an error occurred while finding the
+ * NOTE: Don't enter this case if an error occurred while finding the
* region (as above)
*/
/* if drawing polygon and enable on back, must move stroke */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 904132b8876..7ad61671b1b 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -171,6 +171,7 @@ void create_vgroups_from_armature(struct ReportList *reports, struct Scene *scen
/* if bone is already in list, pass it as param to ignore it */
void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone);
void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep);
+void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names);
void undo_push_armature(struct bContext *C, const char *name);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index a913421d12c..682db20af55 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1993,7 +1993,7 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but)
static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
{
BLI_assert(but->type == UI_BTYPE_TEXT);
- return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr && but->drawstr[0]);
+ return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr[0]);
}
static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index a761bcfdf5e..734cd02a056 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -2963,7 +2963,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
if (pbuf) {
if (ui_but_is_utf8(but)) {
- buf_len -= BLI_utf8_invalid_strip(pbuf, buf_len);
+ buf_len -= BLI_utf8_invalid_strip(pbuf, (size_t)buf_len);
}
ui_textedit_insert_buf(but, data, pbuf, buf_len);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index b02a909d009..7262b453e02 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -581,6 +581,9 @@ static void ui_item_enum_expand(
UI_block_layout_set_current(block, layout_radial);
}
else {
+ if (layout->item.type == ITEM_LAYOUT_RADIAL) {
+ layout_radial = layout;
+ }
UI_block_layout_set_current(block, layout);
}
}
@@ -593,8 +596,9 @@ static void ui_item_enum_expand(
for (item = item_array; item->identifier; item++) {
if (!item->identifier[0]) {
- if (radial)
+ if (radial && layout_radial) {
uiItemS(layout_radial);
+ }
continue;
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index c57b0215d46..8f004bcf72b 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -684,27 +684,38 @@ static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_
/* now we need to find the edge that isnt connected to this element */
BM_select_history_clear(bm);
+ /* Notes on hidden geometry:
+ * - un-hide the face since its possible hidden was copied when copying surrounding face attributes.
+ * - un-hide before adding to select history
+ * since we may extend into an existing, hidden vert/edge.
+ */
+
+ BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
+ BM_face_select_set(bm, f, false);
+
if (ele_desel->head.htype == BM_VERT) {
BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel);
BLI_assert(f->len == 3);
- BM_face_select_set(bm, f, false);
BM_vert_select_set(bm, (BMVert *)ele_desel, false);
-
BM_edge_select_set(bm, l->next->e, true);
BM_select_history_store(bm, l->next->e);
}
else {
BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel);
BLI_assert(f->len == 4 || f->len == 3);
- BM_face_select_set(bm, f, false);
+
BM_edge_select_set(bm, (BMEdge *)ele_desel, false);
if (f->len == 4) {
- BM_edge_select_set(bm, l->next->next->e, true);
- BM_select_history_store(bm, l->next->next->e);
+ BMEdge *e_active = l->next->next->e;
+ BM_elem_flag_disable(e_active, BM_ELEM_HIDDEN);
+ BM_edge_select_set(bm, e_active, true);
+ BM_select_history_store(bm, e_active);
}
else {
- BM_vert_select_set(bm, l->next->next->v, true);
- BM_select_history_store(bm, l->next->next->v);
+ BMVert *v_active = l->next->next->v;
+ BM_elem_flag_disable(v_active, BM_ELEM_HIDDEN);
+ BM_vert_select_set(bm, v_active, true);
+ BM_select_history_store(bm, v_active);
}
}
}
@@ -758,6 +769,14 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
else
#endif
{
+ /* Newly created faces may include existing hidden edges,
+ * copying face data from surrounding, may have copied hidden face flag too.
+ *
+ * Important that faces use flushing since 'edges.out' wont include hidden edges that already existed.
+ */
+ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true);
+ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, false);
+
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
}
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 111afcdc7a7..edd7b5dd1be 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -41,6 +41,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index d30022c01f8..b5fbe4ba586 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2133,7 +2133,7 @@ enum {
};
static int tag_localizable_looper(
- void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int UNUSED(cd_flag))
+ void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int UNUSED(cb_flag))
{
if (*id_pointer) {
(*id_pointer)->tag &= ~LIB_TAG_DOIT;
@@ -2170,12 +2170,12 @@ static void tag_localizable_objects(bContext *C, const int mode)
*/
for (Object *object = bmain->object.first; object; object = object->id.next) {
if ((object->id.tag & LIB_TAG_DOIT) == 0) {
- BKE_library_foreach_ID_link(&object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(NULL, &object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
}
if (object->data) {
ID *data_id = (ID *) object->data;
if ((data_id->tag & LIB_TAG_DOIT) == 0) {
- BKE_library_foreach_ID_link(data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(NULL, data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
}
}
}
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index f1b7186f8a1..b5131df3eaa 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -45,6 +45,7 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_rand.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -1131,7 +1132,7 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op)
{
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, primbase->object->id.name + 2, true);
+ BLI_string_flip_side_name(name_flip, primbase->object->id.name + 2, true, sizeof(name_flip));
if (!STREQ(name_flip, primbase->object->id.name + 2)) {
Object *ob = (Object *)BKE_libblock_find_name(ID_OB, name_flip);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 991025a4d5d..729dd9dc57b 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -36,6 +36,7 @@
#include "BLI_array_utils.h"
#include "BLI_bitmap.h"
#include "BLI_stack.h"
+#include "BLI_string_utils.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -275,7 +276,7 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
int mirrdef;
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, defgroup->name, false);
+ BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
mirrdef = defgroup_name_index(ob, name_flip);
if (mirrdef == -1) {
if (BKE_defgroup_new(ob, name_flip)) {
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 9fc96e06299..0764f586de9 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -170,6 +170,8 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
unsigned char col1a[3], col2a[3];
unsigned char col1b[3], col2b[3];
+ const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS);
+
/* get theme colors */
UI_GetThemeColor3ubv(TH_BACK, col2);
@@ -247,8 +249,36 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
}
case ANIMTYPE_GROUP:
{
- if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
- else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
+ bActionGroup *agrp = ale->data;
+ if (show_group_colors && agrp->customCol) {
+ if (sel) {
+ unsigned char *cp = (unsigned char *)agrp->cs.select;
+ glColor4ub(cp[0], cp[1], cp[2], 0x45);
+ }
+ else {
+ unsigned char *cp = (unsigned char *)agrp->cs.solid;
+ glColor4ub(cp[0], cp[1], cp[2], 0x1D);
+ }
+ }
+ else {
+ if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
+ else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
+ }
+ break;
+ }
+ case ANIMTYPE_FCURVE:
+ {
+ FCurve *fcu = ale->data;
+ if (show_group_colors && fcu->grp && fcu->grp->customCol) {
+ unsigned char *cp = (unsigned char *)fcu->grp->cs.active;
+
+ if (sel) glColor4ub(cp[0], cp[1], cp[2], 0x65);
+ else glColor4ub(cp[0], cp[1], cp[2], 0x0B);
+ }
+ else {
+ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
+ else glColor4ub(col2[0], col2[1], col2[2], 0x22);
+ }
break;
}
default:
diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c
index 074368a82c5..1559515221e 100644
--- a/source/blender/editors/space_logic/logic_ops.c
+++ b/source/blender/editors/space_logic/logic_ops.c
@@ -37,6 +37,7 @@
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 874e54ba5e7..3de44174d6a 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -47,8 +47,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BKE_action.h"
#include "BKE_context.h"
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 3243579f7d0..5355b8012db 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -502,51 +502,57 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
void nla_buttons_register(ARegionType *art)
{
PanelType *pt;
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animdata");
strcpy(pt->idname, "NLA_PT_animdata");
strcpy(pt->label, N_("Animation Data"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_animdata;
pt->poll = nla_animdata_panel_poll;
pt->flag = PNL_DEFAULT_CLOSED;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track");
strcpy(pt->idname, "NLA_PT_track");
strcpy(pt->label, N_("Active Track"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_track;
pt->poll = nla_track_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_properties");
strcpy(pt->label, N_("Active Strip"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_properties;
pt->poll = nla_strip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_actionclip");
strcpy(pt->label, N_("Action Clip"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_actclip;
pt->poll = nla_strip_actclip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation");
strcpy(pt->idname, "NLA_PT_evaluation");
strcpy(pt->label, N_("Evaluation"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_evaluation;
pt->poll = nla_strip_eval_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers");
strcpy(pt->idname, "NLA_PT_modifiers");
strcpy(pt->label, N_("Modifiers"));
+ strcpy(pt->category, "Modifiers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_modifiers;
pt->poll = nla_strip_eval_panel_poll;
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 7bad109be60..41ae40fc961 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1629,17 +1629,6 @@ static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(col, ptr, "use_antialias_z", 0, NULL, ICON_NONE);
}
-
-static void node_composit_buts_hue_sat(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "color_hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "color_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "color_value", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-}
-
static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
@@ -2580,9 +2569,6 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_ALPHAOVER:
ntype->draw_buttons = node_composit_buts_alphaover;
break;
- case CMP_NODE_HUE_SAT:
- ntype->draw_buttons = node_composit_buts_hue_sat;
- break;
case CMP_NODE_TEXTURE:
ntype->draw_buttons = node_buts_texture;
break;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 33a5a7ca7b7..99242fd12f9 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -40,6 +40,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_mempool.h"
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index df3620843ad..f603fa1b0f1 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -248,6 +248,7 @@ static int text_open_exec(bContext *C, wmOperator *op)
pprop = op->customdata;
if (pprop->prop) {
+ id_us_ensure_real(&text->id);
RNA_id_pointer_create(&text->id, &idptr);
RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
RNA_property_update(C, &pprop->ptr, pprop->prop);
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index cf738de0202..f0e65f84205 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -75,6 +75,80 @@ void draw_motion_paths_init(View3D *v3d, ARegion *ar)
glLoadMatrixf(rv3d->viewmat);
}
+/* set color
+* - more intense for active/selected bones, less intense for unselected bones
+* - black for before current frame, green for current frame, blue for after current frame
+* - intensity decreases as distance from current frame increases
+*
+* If the user select custom color, the color is replaced for the color selected in UI panel
+* - 75% Darker color is used for previous frames
+* - 50% Darker color for current frame
+* - User selected color for next frames
+*/
+static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra,
+ float prev_color[3], float frame_color[3], float next_color[3])
+{
+ int frame = sfra + i;
+ int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */
+
+#define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min)
+ float intensity; /* how faint */
+
+ if (frame < CFRA) {
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ /* Custom color: previous frames color is darker than current frame */
+ glColor3fv(prev_color);
+ }
+ else {
+ /* black - before cfra */
+ if (sel) {
+ /* intensity = 0.5f; */
+ intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f);
+ }
+ else {
+ /* intensity = 0.8f; */
+ intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f);
+ }
+ UI_ThemeColorBlend(TH_WIRE, blend_base, intensity);
+ }
+ }
+ else if (frame > CFRA) {
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ /* Custom color: next frames color is equal to user selected color */
+ glColor3fv(next_color);
+ }
+ else {
+ /* blue - after cfra */
+ if (sel) {
+ /* intensity = 0.5f; */
+ intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f);
+ }
+ else {
+ /* intensity = 0.8f; */
+ intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f);
+ }
+ UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity);
+ }
+ }
+ else {
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ /* Custom color: current frame color is slightly darker than user selected color */
+ glColor3fv(frame_color);
+ }
+ else {
+ /* green - on cfra */
+ if (sel) {
+ intensity = 0.5f;
+ }
+ else {
+ intensity = 0.99f;
+ }
+ UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10);
+ }
+ }
+#undef SET_INTENSITY
+}
+
/* Draw the given motion path for an Object or a Bone
* - assumes that the viewport has already been initialized properly
* i.e. draw_motion_paths_init() has been called
@@ -86,6 +160,28 @@ void draw_motion_path_instance(Scene *scene,
bMotionPathVert *mpv, *mpv_start;
int i, stepsize = avs->path_step;
int sfra, efra, sind, len;
+ float prev_color[3];
+ float frame_color[3];
+ float next_color[3];
+
+ /* Custom color - Previous frames: color is darker than current frame */
+ prev_color[0] = mpath->color[0] * 0.25f;
+ prev_color[1] = mpath->color[1] * 0.25f;
+ prev_color[2] = mpath->color[2] * 0.25f;
+
+ /* Custom color - Current frame: color is slightly darker than user selected color */
+ frame_color[0] = mpath->color[0] * 0.50f;
+ frame_color[1] = mpath->color[1] * 0.50f;
+ frame_color[2] = mpath->color[2] * 0.50f;
+
+ /* Custom color - Next frames: color is equal to user selection */
+ next_color[0] = mpath->color[0];
+ next_color[1] = mpath->color[1];
+ next_color[2] = mpath->color[2];
+
+ /* Save old line width */
+ GLfloat old_width;
+ glGetFloatv(GL_LINE_WIDTH, &old_width);
/* get frame ranges */
if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
@@ -130,64 +226,27 @@ void draw_motion_path_instance(Scene *scene,
mpv_start = (mpath->points + sind);
/* draw curve-line of path */
-
- glBegin(GL_LINE_STRIP);
- for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
- short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT);
- float intensity; /* how faint */
-
- int frame = sfra + i;
- int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */
-
- /* set color
- * - more intense for active/selected bones, less intense for unselected bones
- * - black for before current frame, green for current frame, blue for after current frame
- * - intensity decreases as distance from current frame increases
- */
-#define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min)
- if (frame < CFRA) {
- /* black - before cfra */
- if (sel) {
- /* intensity = 0.5f; */
- intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f);
- }
- else {
- /* intensity = 0.8f; */
- intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f);
- }
- UI_ThemeColorBlend(TH_WIRE, blend_base, intensity);
- }
- else if (frame > CFRA) {
- /* blue - after cfra */
- if (sel) {
- /* intensity = 0.5f; */
- intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f);
- }
- else {
- /* intensity = 0.8f; */
- intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f);
- }
- UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity);
- }
- else {
- /* green - on cfra */
- if (sel) {
- intensity = 0.5f;
- }
- else {
- intensity = 0.99f;
- }
- UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10);
+ /* Draw lines only if line drawing option is enabled */
+ if (mpath->flag & MOTIONPATH_FLAG_LINES) {
+ /* set line thickness */
+ glLineWidth(mpath->line_thickness);
+
+ glBegin(GL_LINE_STRIP);
+ for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
+ short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT);
+ /* Set color */
+ set_motion_path_color(scene, mpath, i, sel, sfra, efra, prev_color, frame_color, next_color);
+ /* draw a vertex with this color */
+ glVertex3fv(mpv->co);
}
-#undef SET_INTENSITY
- /* draw a vertex with this color */
- glVertex3fv(mpv->co);
+ glEnd();
+ /* back to old line thickness */
+ glLineWidth(old_width);
}
-
- glEnd();
-
- glPointSize(1.0);
+
+ /* Point must be bigger than line thickness */
+ glPointSize(mpath->line_thickness + 1.0);
/* draw little black point at each frame
* NOTE: this is not really visible/noticeable
@@ -197,8 +256,13 @@ void draw_motion_path_instance(Scene *scene,
glVertex3fv(mpv->co);
glEnd();
- /* Draw little white dots at each framestep value */
- UI_ThemeColor(TH_TEXT_HI);
+ /* Draw little white dots at each framestep value or replace with custom color */
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ glColor4fv(mpath->color);
+ }
+ else {
+ UI_ThemeColor(TH_TEXT_HI);
+ }
glBegin(GL_POINTS);
for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize)
glVertex3fv(mpv->co);
@@ -208,11 +272,11 @@ void draw_motion_path_instance(Scene *scene,
* NOTE: this is only done when keyframes are shown, since this adds similar types of clutter
*/
if ((avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) &&
- (sfra < CFRA) && (CFRA <= efra))
+ (sfra < CFRA) && (CFRA <= efra))
{
UI_ThemeColor(TH_CFRAME);
- glPointSize(6.0f);
+ glPointSize(mpath->line_thickness + 5.0);
glBegin(GL_POINTS);
mpv = mpv_start + (CFRA - sfra);
glVertex3fv(mpv->co);
@@ -289,7 +353,13 @@ void draw_motion_path_instance(Scene *scene,
UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col);
col[3] = 255;
- glPointSize(4.0f);
+ /* if custom, point must be bigger than line */
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ glPointSize(mpath->line_thickness + 3.0);
+ }
+ else {
+ glPointSize(4.0f);
+ }
glColor3ubv(col);
glBegin(GL_POINTS);
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index 95a2df68e4a..149144d969a 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -2463,6 +2463,10 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base
if (end <= start)
return;
+ /* prevent infinite loops if this is set to 0 - T49527 */
+ if (arm->ghostsize < 1)
+ arm->ghostsize = 1;
+
stepsize = (float)(arm->ghostsize);
range = (float)(end - start);
@@ -2608,7 +2612,11 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
calc_action_range(adt->action, &start, &end, 0);
if (start == end)
return;
-
+
+ /* prevent infinite loops if this is set to 0 - T49527 */
+ if (arm->ghostsize < 1)
+ arm->ghostsize = 1;
+
stepsize = (float)(arm->ghostsize);
range = (float)(arm->ghostep) * stepsize + 0.5f; /* plus half to make the for loop end correct */
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 20c62e91d01..31ffa019e4e 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -2176,7 +2176,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
calculateCenter(t);
if (event) {
- initMouseInput(t, &t->mouse, t->center2d, event->mval);
+ initMouseInput(t, &t->mouse, t->center2d, event->mval, event->shift);
}
switch (mode) {
@@ -8495,7 +8495,7 @@ static void initTimeScale(TransInfo *t)
center[1] = t->mouse.imval[1];
/* force a reinit with the center2d used here */
- initMouseInput(t, &t->mouse, center, t->mouse.imval);
+ initMouseInput(t, &t->mouse, center, t->mouse.imval, false);
initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index a59f9dc43dd..7ea4448a44e 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -728,7 +728,7 @@ typedef enum {
INPUT_CUSTOM_RATIO_FLIP,
} MouseInputMode;
-void initMouseInput(TransInfo *t, MouseInput *mi, const float center[2], const int mval[2]);
+void initMouseInput(TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision);
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode);
eRedrawFlag handleMouseInput(struct TransInfo *t, struct MouseInput *mi, const struct wmEvent *event);
void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, const int mval[2], float output[3]);
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index 9b7d19eacd5..42cc918ec8c 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -234,10 +234,10 @@ static void InputAngleSpring(TransInfo *t, MouseInput *mi, const double mval[2],
output[1] = toutput[0];
}
-void initMouseInput(TransInfo *UNUSED(t), MouseInput *mi, const float center[2], const int mval[2])
+void initMouseInput(TransInfo *UNUSED(t), MouseInput *mi, const float center[2], const int mval[2], const bool precision)
{
mi->factor = 0;
- mi->precision = 0;
+ mi->precision = precision;
mi->center[0] = center[0];
mi->center[1] = center[1];
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 90a4aa3614d..058af768885 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -42,7 +42,7 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
-#include "BLI_path_util.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index f8bb124e943..87ac54b2bd9 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -569,7 +569,9 @@ static void initSnappingMode(TransInfo *t)
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
(obedit == NULL) ) // Object Mode
{
- t->tsnap.modeSelect = SNAP_NOT_SELECTED;
+ /* In "Edit Strokes" mode, Snap tool can perform snap to selected or active objects (see T49632)
+ * TODO: perform self snap in gpencil_strokes */
+ t->tsnap.modeSelect = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_ALL : SNAP_NOT_SELECTED;
}
else {
/* Grid if snap is not possible */
@@ -1214,7 +1216,7 @@ bool snapObjectsTransform(
t->tsnap.object_context,
t->scene->toolsettings->snap_mode,
&(const struct SnapObjectParams){
- .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
mval, dist_px, NULL,
@@ -1304,7 +1306,7 @@ bool peelObjectsTransform(
t->tsnap.object_context,
mval,
&(const struct SnapObjectParams){
- .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
use_peel_object,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 02900d7022c..85209b07677 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -59,6 +59,24 @@
#include "transform.h"
+enum eViewProj {
+ VIEW_PROJ_NONE = -1,
+ VIEW_PROJ_ORTHO = 0,
+ VIEW_PROJ_PERSP = -1,
+};
+
+typedef struct SnapData {
+ short snap_to;
+ float mval[2];
+ float ray_origin[3];
+ float ray_start[3];
+ float ray_dir[3];
+ float pmat[4][4]; /* perspective matrix */
+ float win_half[2];/* win x and y */
+ enum eViewProj view_proj;
+ float depth_range[2];
+} SnapData;
+
typedef struct SnapObjectData {
enum {
SNAP_MESH = 1,
@@ -110,12 +128,6 @@ 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);
@@ -223,6 +235,12 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
/** \Common utilities
* \{ */
+MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3])
+{
+ float dvec[3];
+ sub_v3_v3v3(dvec, co, ray_start);
+ return dot_v3v3(dvec, ray_dir);
+}
/**
* Struct that kepts basic information about a BVHTree build from a editmesh.
@@ -232,60 +250,40 @@ typedef struct BVHTreeFromMeshType {
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);
-}
-
/**
- * From a threshold (maximum distance to snap in pixels) returns:
+ * Generates a struct with the immutable parameters that will be used on all objects.
*
- * - 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.
+ * \param snap_to: Element to snap, Vertice, Edge or Face.
+ * \param view_proj: ORTHO or PERSP.
+ * Currently only works one at a time, but can eventually operate as flag.
+ *
+ * \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_direction: Unit length direction of the ray.
+ * \param depth_range: distances of clipe plane min and clip plane max;
*/
-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];
-}
-
-static const float *get_vert_co(const BVHTreeFromMeshType *meshdata, const int index)
+static void snap_data_set(
+ SnapData *snapdata,
+ const ARegion *ar, const unsigned short snap_to, const enum eViewProj view_proj,
+ const float mval[2], const float ray_origin[3], const float ray_start[3],
+ const float ray_direction[3], const float depth_range[2])
{
- 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;
+ if (ar) {
+ copy_m4_m4(snapdata->pmat, ((RegionView3D *)ar->regiondata)->persmat);
+ snapdata->win_half[0] = ar->winx / 2;
+ snapdata->win_half[1] = ar->winy / 2;
+ }
+ if (mval) {
+ copy_v2_v2(snapdata->mval, mval);
+ }
+ snapdata->snap_to = snap_to;
+ copy_v3_v3(snapdata->ray_origin, ray_origin);
+ copy_v3_v3(snapdata->ray_start, ray_start);
+ copy_v3_v3(snapdata->ray_dir, ray_direction);
+ snapdata->view_proj = view_proj;
+ copy_v2_v2(snapdata->depth_range, depth_range);
}
static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, float r_no[3])
@@ -336,87 +334,13 @@ static void get_edge_verts(
}
}
-#define V3_MUL_ELEM(a, b) \
- (a)[0] * (b)[0], \
- (a)[1] * (b)[1], \
- (a)[2] * (b)[2]
-
-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)};
-
- float depth, dist_sq;
- dist_sq = dist_squared_to_ray_v3(origin_sc, dir_sc, vco_sc, &depth);
-
- if (depth < ray_depth_range[0]) {
- return false;
- }
-
- if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
- *dist_to_ray_sq = dist_sq;
-
- copy_v3_v3(r_co, vco);
-
- *ray_depth = depth;
- return true;
- }
- return false;
-}
-
-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)};
-
- 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 (depth < ray_depth_range[0]) {
- return false;
- }
-
- if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
- *dist_to_ray_sq = dist_sq;
-
- 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])
+ const float depth_range[2], const float mval[2], const float co[3],
+ float pmat[4][4], const float win_half[2], const bool is_persp,
+ float *dist_px_sq, float r_co[3])
{
float depth;
- float(*pmat)[4] = projectdefs->pmat;
- if (view_proj == VIEW_PROJ_PERSP) {
+ if (is_persp) {
depth = mul_project_m4_v3_zfac(pmat, co);
if (depth < depth_range[0] || depth > depth_range[1]) {
return false;
@@ -428,109 +352,105 @@ static bool test_projected_vert_dist(
(dot_m4_v3_row_y(pmat, co) + pmat[3][1]),
};
- if (view_proj == VIEW_PROJ_PERSP) {
+ if (is_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];
+ co2d[0] *= win_half[0];
+ co2d[1] *= win_half[1];
const float dist_sq = len_squared_v2v2(mval, co2d);
- if (dist_sq < projectdefs->dist_px_sq) {
+ if (dist_sq < *dist_px_sq) {
copy_v3_v3(r_co, co);
- projectdefs->dist_px_sq = dist_sq;
+ *dist_px_sq = dist_sq;
return true;
}
return false;
}
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])
+ const float depth_range[2], const float mval[2],
+ float pmat[4][4], const float win_half[2], const bool is_persp,
+ const float ray_start[3], const float ray_dir[3],
+ const float va[3], const float vb[3],
+ float *dist_px_sq, float r_co[3])
{
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);
+ dist_squared_ray_to_seg_v3(ray_start, ray_dir, va, vb, tmp_co, &depth);
+ return test_projected_vert_dist(depth_range, mval, tmp_co, pmat, win_half, is_persp, dist_px_sq, r_co);
}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \Walk DFS
- * \{ */
-typedef struct Object_Nearest2dPrecalc {
+typedef struct Nearest2dPrecalc {
float ray_origin_local[3];
float ray_direction_local[3];
float ray_inv_dir[3];
- PreDefProject projectdefs;
+ float ray_min_dist;
+ float pmat[4][4]; /* perspective matrix multiplied by object matrix */
+ bool is_persp;
+ float win_half[2];
+
float mval[2];
bool sign[3];
- bool r_axis_closest[3];
- float depth_range[2];
+} Nearest2dPrecalc;
- 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])
+/**
+ * \param lpmat: Perspective matrix multiplied by object matrix
+ */
+static void dist_squared_to_projected_aabb_precalc(
+ struct Nearest2dPrecalc *neasrest_precalc,
+ float lpmat[4][4], bool is_persp, const float win_half[2],
+ const float ray_min_dist, const float mval[2],
+ const float ray_origin_local[3], const float ray_direction_local[3])
{
- precalc_project(&neasrest_precalc->projectdefs, ar, dist_px, obmat);
+ copy_m4_m4(neasrest_precalc->pmat, lpmat);
+ neasrest_precalc->is_persp = is_persp;
+ copy_v2_v2(neasrest_precalc->win_half, win_half);
+ neasrest_precalc->ray_min_dist = ray_min_dist;
+
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_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)
+static float dist_squared_to_projected_aabb(
+ struct Nearest2dPrecalc *data,
+ const float bbmin[3], const float bbmax[3],
+ bool r_axis_closest[3])
{
- 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;
+ local_bvmin[0] = bbmax[0];
+ local_bvmax[0] = bbmin[0];
}
else {
- local_bvmin[0] = bounds[0].min;
- local_bvmax[0] = bounds[0].max;
+ local_bvmin[0] = bbmin[0];
+ local_bvmax[0] = bbmax[0];
}
if (data->sign[1]) {
- local_bvmin[1] = bounds[1].max;
- local_bvmax[1] = bounds[1].min;
+ local_bvmin[1] = bbmax[1];
+ local_bvmax[1] = bbmin[1];
}
else {
- local_bvmin[1] = bounds[1].min;
- local_bvmax[1] = bounds[1].max;
+ local_bvmin[1] = bbmin[1];
+ local_bvmax[1] = bbmax[1];
}
if (data->sign[2]) {
- local_bvmin[2] = bounds[2].max;
- local_bvmax[2] = bounds[2].min;
+ local_bvmin[2] = bbmax[2];
+ local_bvmax[2] = bbmin[2];
}
else {
- local_bvmin[2] = bounds[2].min;
- local_bvmax[2] = bounds[2].max;
+ local_bvmin[2] = bbmin[2];
+ local_bvmax[2] = bbmax[2];
}
const float tmin[3] = {
@@ -543,7 +463,9 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
(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],
};
+ /* `va` and `vb` are the coordinates of the AABB edge closest to the ray */
float va[3], vb[3];
+ /* `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB */
float rtmin, rtmax;
int main_axis;
@@ -551,38 +473,38 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
rtmax = tmax[0];
va[0] = vb[0] = local_bvmax[0];
main_axis = 3;
- data->r_axis_closest[0] = data->sign[0];
+ 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];
+ 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];
+ r_axis_closest[2] = data->sign[2];
}
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];
+ 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];
+ 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];
+ r_axis_closest[2] = !data->sign[2];
}
if (main_axis < 0) {
main_axis += 3;
@@ -590,22 +512,34 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
/* if rtmin < rtmax, ray intersect `AABB` */
if (rtmin <= rtmax) {
+#define IGNORE_BEHIND_RAY
#ifdef IGNORE_BEHIND_RAY
- /* `if rtmax < depth_min`, the whole `AABB` is behind us */
- if (rtmax < min_depth) {
- return fallback;
+ /* `if rtmax < depth_min`, the hit is behind us */
+ if (rtmax < data->ray_min_dist) {
+ /* Test if the entire AABB is behind us */
+ float depth = depth_get(
+ local_bvmax, data->ray_origin_local, data->ray_direction_local);
+ if (depth < (data->ray_min_dist)) {
+ return FLT_MAX;
+ }
}
#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;
+ r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj);
+ return 0.0f;
}
#ifdef IGNORE_BEHIND_RAY
- /* `if rtmin < depth_min`, the whole `AABB` is behing us */
- else if (rtmin < min_depth) {
- return fallback;
+ /* `if rtmin < depth_min`, the hit is behing us */
+ else if (rtmin < data->ray_min_dist) {
+ /* Test if the entire AABB is behind us */
+ float depth = depth_get(
+ local_bvmax, data->ray_origin_local, data->ray_direction_local);
+ if (depth < (data->ray_min_dist)) {
+ return FLT_MAX;
+ }
}
#endif
+#undef IGNORE_BEHIND_RAY
if (data->sign[main_axis]) {
va[main_axis] = local_bvmax[main_axis];
vb[main_axis] = local_bvmin[main_axis];
@@ -616,31 +550,35 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
}
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 (*pmat)[4] = data->pmat;
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] + pmat[main_axis][0] * scale),
+ (va2d[1] + pmat[main_axis][1] * scale),
};
- va2d[0] /= depth_a;
- va2d[1] /= depth_a;
+ if (data->is_persp) {
+ float depth_a = mul_project_m4_v3_zfac(pmat, va);
+ float depth_b = depth_a + pmat[main_axis][3] * scale;
+ va2d[0] /= depth_a;
+ va2d[1] /= depth_a;
+ vb2d[0] /= depth_b;
+ vb2d[1] /= depth_b;
+ }
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];
+ va2d[0] *= data->win_half[0];
+ va2d[1] *= data->win_half[1];
+ vb2d[0] *= data->win_half[0];
+ vb2d[1] *= data->win_half[1];
//float dvec[2], edge[2], rdist;
//sub_v2_v2v2(dvec, data->mval, va2d);
@@ -653,73 +591,138 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
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;
+ 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;
+ r_axis_closest[main_axis] = false;
}
else {
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;
+ r_axis_closest[main_axis] = lambda < 0.5f;
}
}
else {
rdist = len_squared_v2v2(data->mval, va2d);
}
- return rdist < data->projectdefs.dist_px_sq;
+ return rdist;
+}
+
+static float dist_squared_to_projected_aabb_simple(
+ float lpmat[4][4], const float win_half[2],
+ const float ray_min_dist, const float mval[2],
+ const float ray_origin_local[3], const float ray_direction_local[3],
+ const float bbmin[3], const float bbmax[3])
+{
+ struct Nearest2dPrecalc data;
+ dist_squared_to_projected_aabb_precalc(
+ &data, lpmat, true, win_half, ray_min_dist,
+ mval, ray_origin_local, ray_direction_local);
+
+ bool dummy[3] = {true, true, true};
+ return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy);
+}
+
+static float dist_aabb_to_plane(
+ const float bbmin[3], const float bbmax[3],
+ const float plane_co[3], const float plane_no[3])
+{
+ const float local_bvmin[3] = {
+ (plane_no[0] < 0) ? bbmax[0] : bbmin[0],
+ (plane_no[1] < 0) ? bbmax[1] : bbmin[1],
+ (plane_no[2] < 0) ? bbmax[2] : bbmin[2],
+ };
+ return depth_get(local_bvmin, plane_co, plane_no);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \Walk DFS
+ * \{ */
+typedef struct Nearest2dUserData {
+ struct Nearest2dPrecalc data_precalc;
+
+ float dist_px_sq;
+
+ bool r_axis_closest[3];
+
+ float depth_range[2];
+ void *userdata;
+ int index;
+ float co[3];
+ float no[3];
+} Nearest2dUserData;
+
+
+static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data)
+{
+ Nearest2dUserData *data = user_data;
+ const float bbmin[3] = {bounds[0].min, bounds[1].min, bounds[2].min};
+ const float bbmax[3] = {bounds[0].max, bounds[1].max, bounds[2].max};
+ const float rdist = dist_squared_to_projected_aabb(
+ &data->data_precalc, bbmin, bbmax, data->r_axis_closest);
+ return rdist < data->dist_px_sq;
}
static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, void *userdata)
{
- struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+ struct Nearest2dUserData *data = userdata;
+ struct Nearest2dPrecalc *neasrest_precalc = &data->data_precalc;
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))
+ data->depth_range,
+ neasrest_precalc->mval, co,
+ neasrest_precalc->pmat,
+ neasrest_precalc->win_half,
+ neasrest_precalc->is_persp,
+ &data->dist_px_sq,
+ data->co))
{
- copy_vert_no(neasrest_precalc->userdata, index, neasrest_precalc->no);
- neasrest_precalc->index = index;
+ copy_vert_no(data->userdata, index, data->no);
+ data->index = index;
}
return true;
}
static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int index, void *userdata)
{
- struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+ struct Nearest2dUserData *data = userdata;
+ struct Nearest2dPrecalc *neasrest_precalc = &data->data_precalc;
const float *v_pair[2];
- get_edge_verts(neasrest_precalc->userdata, index, v_pair);
+ get_edge_verts(data->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))
+ data->depth_range,
+ neasrest_precalc->mval,
+ neasrest_precalc->pmat,
+ neasrest_precalc->win_half,
+ neasrest_precalc->is_persp,
+ neasrest_precalc->ray_origin_local,
+ neasrest_precalc->ray_direction_local,
+ v_pair[0], v_pair[1],
+ &data->dist_px_sq,
+ data->co))
{
- sub_v3_v3v3(neasrest_precalc->no, v_pair[0], v_pair[1]);
- neasrest_precalc->index = index;
+ sub_v3_v3v3(data->no, v_pair[0], v_pair[1]);
+ data->index = index;
}
return true;
}
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;
+ const bool *r_axis_closest = ((struct Nearest2dUserData *)userdata)->r_axis_closest;
return r_axis_closest[axis];
}
@@ -731,46 +734,56 @@ static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char a
* \{ */
static bool snapArmature(
- 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],
+ SnapData *snapdata,
+ Object *ob, bArmature *arm, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
bool retval = false;
- float ray_start_local[3], ray_normal_local[3];
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ float ray_start_local[3], ray_normal_local[3]; /* Used only in the snap to edges */
+ if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
float imat[4][4];
invert_m4_m4(imat, obmat);
- copy_v3_v3(ray_start_local, origin);
- copy_v3_v3(ray_normal_local, dir);
+ copy_v3_v3(ray_start_local, snapdata->ray_origin);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
mul_m4_v3(imat, ray_start_local);
mul_mat3_m4_v3(imat, ray_normal_local);
}
+ else if (snapdata->snap_to != SCE_SNAP_MODE_VERTEX) { /* Currently only edge and vert */
+ return retval;
+ }
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, obmat);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float lpmat[4][4], dist_px_sq;
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ dist_px_sq = SQUARE(*dist_px);
if (arm->edbo) {
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) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
retval |= test_projected_vert_dist(
- &projectdefs, eBone->head, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, eBone->head,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
retval |= test_projected_vert_dist(
- &projectdefs, eBone->tail, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, eBone->tail,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
break;
case SCE_SNAP_MODE_EDGE:
retval |= test_projected_edge_dist(
- &projectdefs, eBone->head, eBone->tail, ray_start_local, ray_normal_local,
- view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, lpmat,
+ snapdata->win_half, is_persp, ray_start_local, ray_normal_local,
+ eBone->head, eBone->tail,
+ &dist_px_sq, r_loc);
break;
}
}
@@ -785,52 +798,60 @@ static bool snapArmature(
const float *head_vec = pchan->pose_head;
const float *tail_vec = pchan->pose_tail;
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
retval |= test_projected_vert_dist(
- &projectdefs, head_vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, head_vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
retval |= test_projected_vert_dist(
- &projectdefs, tail_vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, tail_vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
break;
case SCE_SNAP_MODE_EDGE:
retval |= test_projected_edge_dist(
- &projectdefs, head_vec, tail_vec, ray_start_local, ray_normal_local,
- view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, lpmat,
+ snapdata->win_half, is_persp, ray_start_local, ray_normal_local,
+ head_vec, tail_vec,
+ &dist_px_sq, r_loc);
break;
}
}
}
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *dist_px = sqrtf(dist_px_sq);
mul_m4_v3(obmat, r_loc);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
return true;
}
return false;
}
static bool snapCurve(
- 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],
+ SnapData *snapdata,
+ Object *ob, Curve *cu, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
bool retval = false;
/* only vertex snapping mode (eg control points and handles) supported for now) */
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ if (snapdata->snap_to != SCE_SNAP_MODE_VERTEX) {
return retval;
}
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, obmat);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float lpmat[4][4], dist_px_sq;
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ dist_px_sq = SQUARE(*dist_px);
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) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
if (ob->mode == OB_MODE_EDIT) {
@@ -840,19 +861,25 @@ static bool snapCurve(
break;
}
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[1],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ 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 |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[0], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[0],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
if (!(nu->bezt[u].f3 & SELECT) &&
!(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
{
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[2], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[2],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
else {
@@ -861,7 +888,9 @@ static bool snapCurve(
break;
}
retval |= test_projected_vert_dist(
- &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bp[u].vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
else {
@@ -869,11 +898,15 @@ static bool snapCurve(
if (nu->pntsu > 1) {
if (nu->bezt) {
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[1],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
else {
retval |= test_projected_vert_dist(
- &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bp[u].vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
}
@@ -885,8 +918,9 @@ static bool snapCurve(
}
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *dist_px = sqrtf(dist_px_sq);
mul_m4_v3(obmat, r_loc);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
return true;
}
return false;
@@ -894,11 +928,10 @@ static bool snapCurve(
/* may extend later (for now just snaps to empty center) */
static bool snapEmpty(
- 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],
+ SnapData *snapdata,
+ Object *ob, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
@@ -909,15 +942,19 @@ static bool snapEmpty(
}
/* for now only vertex supported */
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, NULL);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float dist_px_sq = SQUARE(*dist_px);
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);
+ if (test_projected_vert_dist(
+ snapdata->depth_range, snapdata->mval, tmp_co,
+ snapdata->pmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc)) {
+ *dist_px = sqrtf(dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
retval = true;
}
break;
@@ -930,18 +967,17 @@ static bool snapEmpty(
}
static bool snapCamera(
- 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],
+ const SnapObjectContext *sctx, SnapData *snapdata,
+ Object *object, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, 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);
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float dist_px_sq = SQUARE(*dist_px);
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
bool retval = false;
@@ -962,7 +998,7 @@ static bool snapCamera(
invert_m4_m4(orig_camera_imat, orig_camera_mat);
invert_m4_m4(imat, obmat);
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
MovieTrackingObject *tracking_object;
@@ -1002,7 +1038,9 @@ static bool snapCamera(
mul_m4_v3(vertex_obmat, bundle_pos);
retval |= test_projected_vert_dist(
- &projectdefs, bundle_pos, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, bundle_pos,
+ snapdata->pmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
@@ -1013,7 +1051,8 @@ static bool snapCamera(
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *dist_px = sqrtf(dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
return true;
}
return false;
@@ -1025,57 +1064,10 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
-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,
+ SnapObjectContext *sctx, SnapData *snapdata,
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],
+ bool do_bb,
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
@@ -1084,12 +1076,12 @@ static bool snapDerivedMesh(
{
bool retval = false;
- if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_FACE) {
if (dm->getNumPolys(dm) == 0) {
return retval;
}
}
- else if (snap_to == SCE_SNAP_MODE_EDGE) {
+ else if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
if (dm->getNumEdges(dm) == 0) {
return retval;
}
@@ -1101,7 +1093,9 @@ static bool snapDerivedMesh(
}
{
- bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && (view_proj == VIEW_PROJ_ORTHO);
+ bool need_ray_start_correction_init =
+ (snapdata->snap_to == SCE_SNAP_MODE_FACE) &&
+ (snapdata->view_proj == VIEW_PROJ_ORTHO);
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
@@ -1111,8 +1105,8 @@ static bool snapDerivedMesh(
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);
+ copy_v3_v3(ray_start_local, snapdata->ray_start);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
mul_m4_v3(imat, ray_start_local);
mul_mat3_m4_v3(imat, ray_normal_local);
@@ -1124,6 +1118,17 @@ static bool snapDerivedMesh(
local_depth *= local_scale;
}
+ float lpmat[4][4];
+ float ray_org_local[3];
+ float ray_min_dist;
+ if (ELEM(snapdata->snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ ray_min_dist = snapdata->depth_range[0] * local_scale;
+ }
+
+ copy_v3_v3(ray_org_local, snapdata->ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
if (do_bb) {
BoundBox *bb = BKE_object_boundbox_get(ob);
@@ -1134,19 +1139,27 @@ static bool snapDerivedMesh(
* Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
- /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'dist_px'),
- * scale up so we can snap against verts & edges on the boundbox, see T46816. */
- if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
- BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f);
- bb = &bb_temp;
+ /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see T46816. */
+ if (ELEM(snapdata->snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
+ float dist_px_sq = dist_squared_to_projected_aabb_simple(
+ lpmat, snapdata->win_half, ray_min_dist, snapdata->mval,
+ ray_org_local, ray_normal_local, bb->vec[0], bb->vec[6]);
+ if (dist_px_sq > SQUARE(*dist_px))
+ {
+ return retval;
+ }
}
-
- /* was local_depth, see: T47838 */
- len_diff = BVH_RAYCAST_DIST_MAX;
-
- if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
- return retval;
+ else {
+ /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
+ if (!isect_ray_aabb_v3_simple(
+ ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], NULL, NULL))
+ {
+ return retval;
+ }
}
+ /* was local_depth, see: T47838 */
+ len_diff = dist_aabb_to_plane(bb->vec[0], bb->vec[6], ray_start_local, ray_normal_local);
+ if (len_diff < 0) len_diff = 0.0f;
need_ray_start_correction_init = false;
}
}
@@ -1165,7 +1178,7 @@ static bool snapDerivedMesh(
}
int tree_index = -1;
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_FACE:
tree_index = 2;
break;
@@ -1196,7 +1209,7 @@ static bool snapDerivedMesh(
}
if (treedata && treedata->tree == NULL) {
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_FACE:
bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
break;
@@ -1213,12 +1226,12 @@ static bool snapDerivedMesh(
return retval;
}
- if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (snapdata->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 (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
+ if (snapdata->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.
@@ -1235,18 +1248,20 @@ static bool snapDerivedMesh(
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;
+ /* You need to make sure that ray_start is really far away,
+ * because even in the Orthografic view, in some cases,
+ * the ray can start inside the object (see T50486) */
+ if (len_diff > 400.0f) {
+ /* 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 + snapdata->depth_range[0] * local_scale);
+ local_depth -= len_diff;
+ }
+ else len_diff = 0.0f;
}
else {
len_diff = 0.0f;
@@ -1304,78 +1319,40 @@ static bool snapDerivedMesh(
}
/* 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;
+ Nearest2dUserData neasrest2d = {
+ .dist_px_sq = SQUARE(*dist_px),
+ .r_axis_closest = {1.0f, 1.0f, 1.0f},
+ .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]},
+ .userdata = &treedata_type,
+ .index = -1};
+
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest2d.data_precalc, lpmat,
+ snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half,
+ ray_min_dist, snapdata->mval, ray_org_local, ray_normal_local);
+
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snapdata->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, &neasrest2d);
+
+ if (neasrest2d.index != -1) {
+ copy_v3_v3(r_loc, neasrest2d.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest2d.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
}
- }
- else {
- BVHTreeNearest nearest;
-
- nearest.index = -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;
+ *dist_px = sqrtf(neasrest2d.dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
- 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)
- {
- 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;
-
- retval = true;
- }
+ retval = true;
}
}
@@ -1390,11 +1367,8 @@ static bool snapDerivedMesh(
}
static bool snapEditMesh(
- SnapObjectContext *sctx,
+ SnapObjectContext *sctx, SnapData *snapdata,
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 */
@@ -1403,12 +1377,12 @@ static bool snapEditMesh(
{
bool retval = false;
- if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_FACE) {
if (em->bm->totface == 0) {
return retval;
}
}
- if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
if (em->bm->totedge == 0) {
return retval;
}
@@ -1427,10 +1401,17 @@ static bool snapEditMesh(
invert_m4_m4(imat, obmat);
transpose_m3_m4(timat, imat);
- copy_v3_v3(ray_normal_local, ray_normal);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
mul_mat3_m4_v3(imat, ray_normal_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;
+ }
+
SnapObjectData_EditMesh *sod = NULL;
BVHTreeFromEditMesh *treedata = NULL, treedata_stack;
@@ -1446,7 +1427,7 @@ static bool snapEditMesh(
}
int tree_index = -1;
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_FACE:
tree_index = 2;
break;
@@ -1470,7 +1451,7 @@ static bool snapEditMesh(
}
if (treedata && treedata->tree == NULL) {
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_FACE:
{
BLI_bitmap *looptri_mask = NULL;
@@ -1528,24 +1509,17 @@ static bool snapEditMesh(
return retval;
}
- if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_FACE) {
float ray_start_local[3];
- copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_start_local, snapdata->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).
+ /* 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!
*/
float len_diff = 0.0f;
- if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
+ if (snapdata->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.
*/
@@ -1559,19 +1533,26 @@ static bool snapEditMesh(
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;
+ /* You need to make sure that ray_start is really far away,
+ * because even in the Orthografic view, in some cases,
+ * the ray can start inside the object (see T50486) */
+ if (len_diff > 400.0f) {
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, snapdata->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 + snapdata->depth_range[0] * local_scale);
+ local_depth -= len_diff;
+ }
+ else len_diff = 0.0f;
}
}
if (r_hit_list) {
@@ -1626,78 +1607,47 @@ static bool snapEditMesh(
}
}
else {
- const ARegion *ar = sctx->v3d_data.ar;
-
float ray_org_local[3];
- copy_v3_v3(ray_org_local, ray_origin);
+ copy_v3_v3(ray_org_local, snapdata->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;
+ Nearest2dUserData neasrest2d = {
+ .dist_px_sq = SQUARE(*dist_px),
+ .r_axis_closest = {1.0f, 1.0f, 1.0f},
+ .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]},
+ .userdata = &treedata_type,
+ .index = -1};
+
+ float lpmat[4][4];
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest2d.data_precalc, lpmat,
+ snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half,
+ (snapdata->depth_range[0] * local_scale), snapdata->mval,
+ ray_org_local, ray_normal_local);
+
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snapdata->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, &neasrest2d);
+
+ if (neasrest2d.index != -1) {
+ copy_v3_v3(r_loc, neasrest2d.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest2d.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
}
- }
- else {
- BVHTreeNearest nearest;
-
- nearest.index = -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;
+ *dist_px = sqrtf(neasrest2d.dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
- 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)
- {
- 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;
-
- retval = true;
- }
+ retval = true;
}
}
@@ -1717,11 +1667,9 @@ static bool snapEditMesh(
* \note Duplicate args here are documented at #snapObjectsRay
*/
static bool snapObject(
- SnapObjectContext *sctx,
+ SnapObjectContext *sctx, SnapData *snapdata,
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],
+ bool use_obedit,
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
@@ -1729,12 +1677,6 @@ static bool snapObject(
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- 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) {
@@ -1743,9 +1685,7 @@ static bool snapObject(
if (use_obedit) {
em = BKE_editmesh_from_object(ob);
retval = snapEditMesh(
- sctx, ob, em, obmat, ob_index,
- snap_to, mval, view_proj,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob, em, obmat, ob_index,
ray_depth, dist_px,
r_loc, r_no, r_index,
r_hit_list);
@@ -1762,9 +1702,8 @@ static bool snapObject(
dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
}
retval = snapDerivedMesh(
- sctx, ob, dm, obmat, ob_index,
- snap_to, mval, view_proj, true,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob, dm, obmat, ob_index,
+ true,
ray_depth, dist_px,
r_loc, r_no,
r_index, r_hit_list);
@@ -1772,32 +1711,32 @@ static bool snapObject(
dm->release(dm);
}
}
- else if (snap_to != SCE_SNAP_MODE_FACE) {
+ else if (snapdata->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,
+ snapdata,
+ ob, ob->data, obmat,
+ ray_depth, 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,
+ snapdata,
+ ob, ob->data, obmat,
+ ray_depth, 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,
+ snapdata,
+ ob, obmat,
+ ray_depth, 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,
+ sctx, snapdata, ob, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
}
@@ -1819,18 +1758,9 @@ static bool snapObject(
* 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 snapdata: struct generated in `get_snapdata`.
* \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
* ---------------
@@ -1851,11 +1781,9 @@ static bool snapObject(
*
*/
static bool snapObjectsRay(
- SnapObjectContext *sctx,
- 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],
+ SnapObjectContext *sctx, SnapData *snapdata,
+ const SnapSelect snap_select,
+ const bool use_object_edit_cage,
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
@@ -1878,9 +1806,7 @@ static bool snapObjectsRay(
Object *ob = base_act->object;
retval |= snapObject(
- sctx, ob, ob->obmat, ob_index++,
- false, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob, ob->obmat, ob_index++, false,
ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1914,9 +1840,8 @@ static bool snapObjectsRay(
Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
retval |= snapObject(
- sctx, dupli_snap, dupli_ob->mat, ob_index++,
- use_obedit_dupli, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, dupli_snap, dupli_ob->mat,
+ ob_index++, use_obedit_dupli,
ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1928,9 +1853,7 @@ static bool snapObjectsRay(
Object *ob_snap = use_obedit ? obedit : ob;
retval |= snapObject(
- sctx, ob_snap, ob->obmat, ob_index++,
- use_obedit, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob_snap, ob->obmat, ob_index++, use_obedit,
ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -2033,16 +1956,19 @@ 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],
+ const float UNUSED(ray_start[3]), const float UNUSED(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])
{
const float depth_range[2] = {0.0f, FLT_MAX};
+
+ SnapData snapdata;
+ snap_data_set(&snapdata, sctx->v3d_data.ar, snap_to, VIEW_PROJ_NONE, NULL, r_loc, r_loc, r_no, depth_range);
+
return snapObjectsRay(
- sctx,
- snap_to, params->snap_select, params->use_object_edit_cage, NULL,
- ray_start, ray_start, ray_normal, depth_range,
+ sctx, &snapdata,
+ params->snap_select, params->use_object_edit_cage,
ray_depth, NULL,
r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
@@ -2071,10 +1997,13 @@ bool ED_transform_snap_object_project_ray_all(
float ray_depth_prev = ray_depth;
#endif
+ SnapData snapdata;
+ snap_data_set(&snapdata, sctx->v3d_data.ar, snap_to, VIEW_PROJ_NONE, NULL,
+ ray_start, ray_start, ray_normal, depth_range);
+
bool retval = snapObjectsRay(
- sctx,
- snap_to, params->snap_select, params->use_object_edit_cage, NULL,
- ray_start, ray_start, ray_normal, depth_range,
+ sctx, &snapdata,
+ params->snap_select, params->use_object_edit_cage,
&ray_depth, NULL,
NULL, NULL, NULL, NULL, NULL,
r_hit_list);
@@ -2153,19 +2082,38 @@ static bool transform_snap_context_project_view3d_mixed_impl(
BLI_assert(snap_to_flag != 0);
BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0);
- for (int i = 0; i < 3; i++) {
- if ((snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
- if (use_depth == false) {
- ray_depth = BVH_RAYCAST_DIST_MAX;
+ if (use_depth) {
+ const float dist_px_orig = *dist_px;
+ for (int i = 2; i >= 0; i--) {
+ if (snap_to_flag & (1 << i)) {
+ if (i == 0)
+ *dist_px = dist_px_orig;
+ if (ED_transform_snap_object_project_view3d(
+ sctx,
+ elem_type[i], params,
+ mval, dist_px, &ray_depth,
+ r_co, r_no))
+ {
+ /* 0.01 is a random but small value to prioritizing
+ * the first elements of the loop */
+ ray_depth += 0.01f;
+ is_hit = true;
+ }
}
-
- if (ED_transform_snap_object_project_view3d(
- sctx,
- elem_type[i], params,
- mval, dist_px, &ray_depth,
- r_co, r_no))
- {
- is_hit = true;
+ }
+ }
+ else {
+ for (int i = 0; i < 3; i++) {
+ if (snap_to_flag & (1 << i)) {
+ if (ED_transform_snap_object_project_view3d(
+ sctx,
+ elem_type[i], params,
+ mval, dist_px, &ray_depth,
+ r_co, r_no))
+ {
+ is_hit = true;
+ break;
+ }
}
}
}
@@ -2234,10 +2182,14 @@ bool ED_transform_snap_object_project_view3d_ex(
ray_depth = &ray_depth_fallback;
}
+ SnapData snapdata;
+ const enum eViewProj view_proj = ((RegionView3D *)ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
+ snap_data_set(&snapdata, ar, snap_to, view_proj, mval,
+ ray_origin, ray_start, ray_normal, depth_range);
+
return snapObjectsRay(
- sctx,
- snap_to, params->snap_select, params->use_object_edit_cage,
- mval, ray_origin, ray_start, ray_normal, depth_range,
+ sctx, &snapdata,
+ params->snap_select, params->use_object_edit_cage,
ray_depth, dist_px,
r_loc, r_no, r_index, NULL, NULL, NULL);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 4416b6494f9..0f3ffa8244b 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -1358,7 +1358,7 @@ void mtex_cube_map_refl_from_refldir(
samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color)
{
color = textureCube(ima, reflecteddirection);
- value = 1.0;
+ value = color.a;
}
void mtex_cube_map_refl(
@@ -3536,6 +3536,8 @@ void node_light_path(
out float is_transmission_ray,
out float ray_length,
out float ray_depth,
+ out float diffuse_depth,
+ out float glossy_depth,
out float transparent_depth,
out float transmission_depth)
{
@@ -3548,6 +3550,8 @@ void node_light_path(
is_transmission_ray = 0.0;
ray_length = 1.0;
ray_depth = 1.0;
+ diffuse_depth = 1.0;
+ glossy_depth = 1.0;
transparent_depth = 1.0;
transmission_depth = 1.0;
}
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index f3df9090d41..1083400ece2 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -76,6 +76,8 @@ typedef struct bMotionPath {
int start_frame; /* for drawing paths, the start frame number */
int end_frame; /* for drawing paths, the end frame number */
+ float color[3]; /* optional custom color */
+ int line_thickness; /* line thickness */
int flag; /* baking settings - eMotionPath_Flag */
} bMotionPath;
@@ -84,7 +86,11 @@ typedef enum eMotionPath_Flag {
/* (for bones) path represents the head of the bone */
MOTIONPATH_FLAG_BHEAD = (1 << 0),
/* motion path is being edited */
- MOTIONPATH_FLAG_EDIT = (1 << 1)
+ MOTIONPATH_FLAG_EDIT = (1 << 1),
+ /* Custom colors */
+ MOTIONPATH_FLAG_CUSTOM = (1 << 2),
+ /* Draw lines or only points */
+ MOTIONPATH_FLAG_LINES = (1 << 3)
} eMotionPath_Flag;
/* Visualization General --------------------------- */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 03794bdc9d5..1e2ef0cc7d3 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -596,6 +596,7 @@ typedef struct NodeBilateralBlurData {
short iter, pad;
} NodeBilateralBlurData;
+/* NOTE: Only for do-version code. */
typedef struct NodeHueSat {
float hue, sat, val;
} NodeHueSat;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 85da31667d5..0f6b1276eb3 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1268,12 +1268,51 @@ typedef enum eGP_BrushEdit_SettingsFlag {
GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2),
/* apply brush to thickness */
GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3),
+} eGP_BrushEdit_SettingsFlag;
+
+
+/* Settings for GP Interpolation Operators */
+typedef struct GP_Interpolate_Settings {
+ short flag; /* eGP_Interpolate_SettingsFlag */
+
+ char type; /* eGP_Interpolate_Type - Interpolation Mode */
+ char easing; /* eBezTriple_Easing - Easing mode (if easing equation used) */
+
+ float back; /* BEZT_IPO_BACK */
+ float amplitude, period; /* BEZT_IPO_ELASTIC */
+
+ struct CurveMapping *custom_ipo; /* custom interpolation curve (for use with GP_IPO_CURVEMAP) */
+} GP_Interpolate_Settings;
+
+/* GP_Interpolate_Settings.flag */
+typedef enum eGP_Interpolate_SettingsFlag {
/* apply interpolation to all layers */
- GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS = (1 << 4),
+ GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS = (1 << 0),
/* apply interpolation to only selected */
- GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED = (1 << 5)
+ GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED = (1 << 1),
+} eGP_Interpolate_SettingsFlag;
+
+/* GP_Interpolate_Settings.type */
+typedef enum eGP_Interpolate_Type {
+ /* Traditional Linear Interpolation */
+ GP_IPO_LINEAR = 0,
+
+ /* CurveMap Defined Interpolation */
+ GP_IPO_CURVEMAP = 1,
+
+ /* Easing Equations */
+ GP_IPO_BACK = 3,
+ GP_IPO_BOUNCE = 4,
+ GP_IPO_CIRC = 5,
+ GP_IPO_CUBIC = 6,
+ GP_IPO_ELASTIC = 7,
+ GP_IPO_EXPO = 8,
+ GP_IPO_QUAD = 9,
+ GP_IPO_QUART = 10,
+ GP_IPO_QUINT = 11,
+ GP_IPO_SINE = 12,
+} eGP_Interpolate_Type;
-} eGP_BrushEdit_SettingsFlag;
/* *************************************************************** */
/* Transform Orientations */
@@ -1491,7 +1530,10 @@ typedef struct ToolSettings {
/* Grease Pencil Sculpt */
struct GP_BrushEdit_Settings gp_sculpt;
-
+
+ /* Grease Pencil Interpolation Tool(s) */
+ struct GP_Interpolate_Settings gp_interpolate;
+
/* Grease Pencil Drawing Brushes (bGPDbrush) */
ListBase gp_brushes;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index f97a5735c94..66e6f30feeb 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -262,6 +262,7 @@ extern StructRNA RNA_GPencilLayer;
extern StructRNA RNA_GPencilPalette;
extern StructRNA RNA_GPencilPaletteColor;
extern StructRNA RNA_GPencilBrush;
+extern StructRNA RNA_GPencilInterpolateSettings;
extern StructRNA RNA_GPencilStroke;
extern StructRNA RNA_GPencilStrokePoint;
extern StructRNA RNA_GPencilSculptSettings;
diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c
index a09853eaddc..004acbe4dbd 100644
--- a/source/blender/makesrna/intern/rna_actuator.c
+++ b/source/blender/makesrna/intern/rna_actuator.c
@@ -32,8 +32,9 @@
#include "DNA_actuator_types.h"
#include "DNA_scene_types.h" /* for MAXFRAME */
-#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index 8e42e68ed1e..eea24bfb1e0 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -153,7 +153,20 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
prop = RNA_def_property(srna, "length", PROP_INT, PROP_TIME);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Length", "Number of frames cached");
-
+
+ /* Custom Color */
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Color", "Custom color for motion path");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* Line width */
+ prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "line_thickness");
+ RNA_def_property_range(prop, 1, 6);
+ RNA_def_property_ui_text(prop, "Line thickness", "Line thickness for drawing path");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
/* Settings */
prop = RNA_def_property(srna, "use_bone_head", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_BHEAD);
@@ -164,6 +177,19 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
prop = RNA_def_property(srna, "is_modified", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_EDIT);
RNA_def_property_ui_text(prop, "Edit Path", "Path is being edited");
+
+ /* Use custom color */
+ prop = RNA_def_property(srna, "use_custom_color", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_CUSTOM);
+ RNA_def_property_ui_text(prop, "Custom colors", "Use custom color for this motion path");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* Draw lines between keyframes */
+ prop = RNA_def_property(srna, "lines", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_LINES);
+ RNA_def_property_ui_text(prop, "Lines", "Draw straight lines between keyframe points");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
}
/* --- */
@@ -337,6 +363,7 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
"Number of frames to show after the current frame "
"(only for 'Around Current Frame' Onion-skinning method)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* XXX since this is only for 3d-view drawing */
+
}
/* --- */
diff --git a/source/blender/makesrna/intern/rna_controller.c b/source/blender/makesrna/intern/rna_controller.c
index ed700916584..3fa9d7ef270 100644
--- a/source/blender/makesrna/intern/rna_controller.c
+++ b/source/blender/makesrna/intern/rna_controller.c
@@ -29,6 +29,7 @@
#include "DNA_object_types.h"
#include "DNA_controller_types.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 14da990278c..6e0d6ad2bcd 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -31,6 +31,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -59,6 +60,7 @@ static EnumPropertyItem parent_type_items[] = {
#include "WM_api.h"
+#include "BKE_animsys.h"
#include "BKE_gpencil.h"
#include "BKE_action.h"
@@ -352,10 +354,16 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
bGPdata *gpd = ptr->id.data;
bGPDlayer *gpl = ptr->data;
+ char oldname[128] = "";
+ BLI_strncpy(oldname, gpl->info, sizeof(oldname));
+
/* copy the new name into the name slot */
BLI_strncpy_utf8(gpl->info, value, sizeof(gpl->info));
BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
+
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&gpd->id, "layers", oldname, gpl->info);
}
static void rna_GPencil_use_onion_skinning_set(PointerRNA *ptr, const int value)
@@ -776,11 +784,16 @@ static void rna_GPencilPalette_info_set(PointerRNA *ptr, const char *value)
bGPdata *gpd = ptr->id.data;
bGPDpalette *palette = ptr->data;
+ char oldname[64] = "";
+ BLI_strncpy(oldname, palette->info, sizeof(oldname));
+
/* 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));
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&gpd->id, "palettes", oldname, palette->info);
}
static char *rna_GPencilPalette_path(PointerRNA *ptr)
@@ -813,14 +826,20 @@ 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);
+
+ char oldname[64] = "";
+ BLI_strncpy(oldname, palcolor->info, sizeof(oldname));
/* 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));
+
+ /* rename all strokes */
+ BKE_gpencil_palettecolor_changename(gpd, oldname, palcolor->info);
+
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&gpd->id, "colors", oldname, palcolor->info);
}
static void rna_GPencilStrokeColor_info_set(PointerRNA *ptr, const char *value)
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index 2d669986485..a5abc8a3be2 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -33,6 +33,7 @@
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index 622c61beaeb..1199cccc4e6 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -27,6 +27,9 @@
#include <stdio.h>
#include <stdlib.h>
+#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
+
#include "RNA_define.h"
#include "RNA_enum_types.h"
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index cd48bc1a3df..ff9873fb3d1 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -241,7 +241,7 @@ void RNA_api_mesh(StructRNA *srna)
RNA_def_function_ui_description(func, "Free split vertex normals");
func = RNA_def_function(srna, "split_faces", "BKE_mesh_split_faces");
- RNA_def_function_ui_description(func, "Spli faces based on the edge angle");
+ RNA_def_function_ui_description(func, "Split faces based on the edge angle");
func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
@@ -320,4 +320,3 @@ void RNA_api_mesh(StructRNA *srna)
}
#endif
-
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 15fbea8381f..18f053f6d2a 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -4431,34 +4431,6 @@ static void def_cmp_alpha_over(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_cmp_hue_saturation(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeHueSat", "storage");
-
- prop = RNA_def_property(srna, "color_hue", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "hue");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_default(prop, 0.5f);
- RNA_def_property_ui_text(prop, "Hue", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "color_saturation", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sat");
- RNA_def_property_range(prop, 0.0f, 2.0f);
- RNA_def_property_ui_text(prop, "Saturation", "");
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "color_value", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "val");
- RNA_def_property_range(prop, 0.0f, 2.0f);
- RNA_def_property_ui_text(prop, "Value", "");
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
static void def_cmp_blur(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 362baed1e7c..95dab13571d 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -45,6 +45,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "BLI_string_utils.h"
+
#include "BLT_translation.h"
#include "rna_internal.h"
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 99d57147248..28ce63a61bd 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -40,6 +40,7 @@
#include "DNA_scene_types.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_property.c b/source/blender/makesrna/intern/rna_property.c
index 07bdbb03357..fb70870f49b 100644
--- a/source/blender/makesrna/intern/rna_property.c
+++ b/source/blender/makesrna/intern/rna_property.c
@@ -31,6 +31,7 @@
#include "DNA_object_types.h"
#include "BLI_path_util.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 7fe8155cd8c..1efef2b4099 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -40,6 +40,7 @@
#include "IMB_imbuf_types.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -406,9 +407,34 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = {
+ /* interpolation */
+ {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"},
+ {GP_IPO_LINEAR, "LINEAR", ICON_IPO_LINEAR, "Linear", "Straight-line interpolation between A and B (i.e. no ease in/out)"},
+ {GP_IPO_CURVEMAP, "CUSTOM", ICON_IPO_BEZIER, "Custom", "Custom interpolation defined using a curvemap"},
+
+ /* easing */
+ {0, "", 0, N_("Easing (by strength)"), "Predefined inertial transitions, useful for motion graphics (from least to most ''dramatic'')"},
+ {GP_IPO_SINE, "SINE", ICON_IPO_SINE, "Sinusoidal", "Sinusoidal easing (weakest, almost linear but with a slight curvature)"},
+ {GP_IPO_QUAD, "QUAD", ICON_IPO_QUAD, "Quadratic", "Quadratic easing"},
+ {GP_IPO_CUBIC, "CUBIC", ICON_IPO_CUBIC, "Cubic", "Cubic easing"},
+ {GP_IPO_QUART, "QUART", ICON_IPO_QUART, "Quartic", "Quartic easing"},
+ {GP_IPO_QUINT, "QUINT", ICON_IPO_QUINT, "Quintic", "Quintic easing"},
+ {GP_IPO_EXPO, "EXPO", ICON_IPO_EXPO, "Exponential", "Exponential easing (dramatic)"},
+ {GP_IPO_CIRC, "CIRC", ICON_IPO_CIRC, "Circular", "Circular easing (strongest and most dynamic)"},
+
+ {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"},
+ {GP_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"},
+ {GP_IPO_BOUNCE, "BOUNCE", ICON_IPO_BOUNCE, "Bounce", "Exponentially decaying parabolic bounce, like when objects collide"},
+ {GP_IPO_ELASTIC, "ELASTIC", ICON_IPO_ELASTIC, "Elastic", "Exponentially decaying sine wave, like an elastic band"},
+
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
+#include "DNA_color_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
@@ -419,6 +445,7 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "MEM_guardedalloc.h"
#include "BKE_brush.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -447,6 +474,29 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "FRS_freestyle.h"
#endif
+/* Grease Pencil Interpolation settings */
+static char *rna_GPencilInterpolateSettings_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gpencil_interpolate");
+}
+
+static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value)
+{
+ GP_Interpolate_Settings *settings = (GP_Interpolate_Settings *)ptr->data;
+
+ /* NOTE: This cast should be fine, as we have a small + finite set of values (eGP_Interpolate_Type)
+ * that should fit well within a char
+ */
+ settings->type = (char)value;
+
+ /* init custom interpolation curve here now the first time it's used */
+ if ((settings->type == GP_IPO_CURVEMAP) &&
+ (settings->custom_ipo == NULL))
+ {
+ settings->custom_ipo = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ }
+}
+
/* Grease pencil Drawing Brushes */
static bGPDbrush *rna_GPencil_brush_new(ToolSettings *ts, const char *name, int setactive)
{
@@ -2146,6 +2196,73 @@ static int rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr))
#else
+/* Grease Pencil Interpolation tool settings */
+static void rna_def_gpencil_interpolate(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "GPencilInterpolateSettings", NULL);
+ RNA_def_struct_sdna(srna, "GP_Interpolate_Settings");
+ RNA_def_struct_path_func(srna, "rna_GPencilInterpolateSettings_path");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Interpolate Settings",
+ "Settings for Grease Pencil interpolation tools");
+
+ /* flags */
+ prop = RNA_def_property(srna, "interpolate_all_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TOOLFLAG_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_TOOLFLAG_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);
+
+ /* interpolation type */
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_interpolation_mode_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_GPencilInterpolateSettings_type_set", NULL);
+ RNA_def_property_ui_text(prop, "Type",
+ "Interpolation method to use the next time 'Interpolate Sequence' is run");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* easing */
+ prop = RNA_def_property(srna, "easing", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "easing");
+ RNA_def_property_enum_items(prop, rna_enum_beztriple_interpolation_easing_items);
+ RNA_def_property_ui_text(prop, "Easing",
+ "Which ends of the segment between the preceding and following grease pencil frames "
+ "easing interpolation is applied to");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* easing options */
+ prop = RNA_def_property(srna, "back", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "back");
+ RNA_def_property_ui_text(prop, "Back", "Amount of overshoot for 'back' easing");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX); /* only positive values... */
+ RNA_def_property_ui_text(prop, "Amplitude", "Amount to boost elastic bounces for 'elastic' easing");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "period");
+ RNA_def_property_ui_text(prop, "Period", "Time between bounces for elastic easing");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* custom curvemap */
+ prop = RNA_def_property(srna, "interpolation_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "custom_ipo");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Interpolation Curve",
+ "Custom curve to control 'sequence' interpolation between Grease Pencil frames");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+}
+
/* Grease Pencil Drawing Brushes */
static void rna_def_gpencil_brush(BlenderRNA *brna)
{
@@ -2681,7 +2798,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
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", "");
+ RNA_def_property_ui_text(prop, "Grease Pencil Sculpt",
+ "Settings for stroke sculpting tools and brushes");
+
+ prop = RNA_def_property(srna, "gpencil_interpolate", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_interpolate");
+ RNA_def_property_struct_type(prop, "GPencilInterpolateSettings");
+ RNA_def_property_ui_text(prop, "Grease Pencil Interpolate",
+ "Settings for Grease Pencil Interpolation tools");
/* Grease Pencil - Drawing brushes */
prop = RNA_def_property(srna, "gpencil_brushes", PROP_COLLECTION, PROP_NONE);
@@ -7352,6 +7476,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_define_animate_sdna(false);
rna_def_tool_settings(brna);
rna_def_gpencil_brush(brna);
+ rna_def_gpencil_interpolate(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_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 7f405f0fb1f..40aea37d9d2 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -1047,15 +1047,6 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
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");
diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c
index ee24a434486..d0afab7a1e3 100644
--- a/source/blender/makesrna/intern/rna_sensor.c
+++ b/source/blender/makesrna/intern/rna_sensor.c
@@ -32,6 +32,7 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index e68e67586e9..0eab38faca8 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -3937,7 +3937,7 @@ static void rna_def_userdef_system(BlenderRNA *brna)
prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "dpi");
- RNA_def_property_range(prop, 48, 144);
+ RNA_def_property_range(prop, 16, 256);
RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display");
RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index b8ebb375a48..bacfc177432 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -113,6 +113,10 @@ set(SRC
intern/MOD_weightvg_util.h
)
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
if(WITH_ALEMBIC)
add_definitions(-DWITH_ALEMBIC)
list(APPEND INC
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 567505ea45d..2400dbcb898 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -96,7 +96,7 @@ static void foreachObjectLink(
{
ArmatureModifierData *amd = (ArmatureModifierData *) md;
- walk(userData, ob, &amd->object, IDWALK_NOP);
+ walk(userData, ob, &amd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index b049457e640..2b739dc0093 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -95,10 +95,10 @@ static void foreachObjectLink(
{
ArrayModifierData *amd = (ArrayModifierData *) md;
- walk(userData, ob, &amd->start_cap, IDWALK_NOP);
- walk(userData, ob, &amd->end_cap, IDWALK_NOP);
- walk(userData, ob, &amd->curve_ob, IDWALK_NOP);
- walk(userData, ob, &amd->offset_ob, IDWALK_NOP);
+ walk(userData, ob, &amd->start_cap, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->end_cap, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->curve_ob, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->offset_ob, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index da0f5aa3923..f828bc68857 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -101,7 +101,7 @@ static void foreachObjectLink(
{
BooleanModifierData *bmd = (BooleanModifierData *) md;
- walk(userData, ob, &bmd->object, IDWALK_NOP);
+ walk(userData, ob, &bmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 2fe27730370..ddcf1852dc6 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -102,7 +102,7 @@ static void foreachObjectLink(
{
CastModifierData *cmd = (CastModifierData *) md;
- walk(userData, ob, &cmd->object, IDWALK_NOP);
+ walk(userData, ob, &cmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index d15a6fcb1c8..e8c39770a14 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -125,9 +125,15 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
if (clmd) {
/* Actual code uses get_collisionobjects */
+#ifdef WITH_LEGACY_DEPSGRAPH
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");
+#else
+ (void)forest;
+ (void)scene;
+ (void)ob;
+ (void)obNode;
+#endif
}
}
@@ -228,11 +234,11 @@ static void foreachIDLink(ModifierData *md, Object *ob,
ClothModifierData *clmd = (ClothModifierData *) md;
if (clmd->coll_parms) {
- walk(userData, ob, (ID **)&clmd->coll_parms->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&clmd->coll_parms->group, IDWALK_CB_NOP);
}
if (clmd->sim_parms && clmd->sim_parms->effector_weights) {
- walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_CB_NOP);
}
}
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index 9bc96e593fd..09444476bfe 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -89,7 +89,7 @@ static void foreachObjectLink(
{
CurveModifierData *cmd = (CurveModifierData *) md;
- walk(userData, ob, &cmd->object, IDWALK_NOP);
+ walk(userData, ob, &cmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index f5ab28d3d88..a2210893602 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -124,7 +124,7 @@ static void foreachObjectLink(
ObjectWalkFunc walk, void *userData)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
- walk(userData, ob, &dtmd->ob_source, IDWALK_NOP);
+ walk(userData, ob, &dtmd->ob_source, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -179,7 +179,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
/* Only used to check wehther we are operating on org data or not... */
Mesh *me = ob->data;
- MVert *mvert;
const bool invert_vgroup = (dtmd->flags & MOD_DATATRANSFER_INVERT_VGROUP) != 0;
@@ -192,8 +191,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
BLI_SPACE_TRANSFORM_SETUP(space_transform, ob, dtmd->ob_source);
}
- mvert = dm->getVertArray(dm);
- if ((me->mvert == mvert) && (dtmd->data_types & DT_TYPES_AFFECT_MESH)) {
+ MVert *mvert = dm->getVertArray(dm);
+ MEdge *medge = dm->getEdgeArray(dm);
+ if (((me->mvert == mvert) || (me->medge == medge)) && (dtmd->data_types & DT_TYPES_AFFECT_MESH)) {
/* We need to duplicate data here, otherwise setting custom normals, edges' shaprness, etc., could
* modify org mesh, see T43671. */
dm = CDDM_copy(dm);
@@ -211,6 +211,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
if (BKE_reports_contain(&reports, RPT_ERROR)) {
modifier_setError(md, "%s", BKE_reports_string(&reports, RPT_ERROR));
}
+ else if ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) {
+ modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' option in mesh settings");
+ }
else if (dm->getNumVerts(dm) > HIGH_POLY_WARNING || ((Mesh *)(dtmd->ob_source->data))->totvert > HIGH_POLY_WARNING) {
modifier_setError(md, "You are using a rather high poly as source or destination, computation might be slow");
}
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 059e096ddb4..08d118a2026 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -132,7 +132,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
{
DisplaceModifierData *dmd = (DisplaceModifierData *) md;
- walk(userData, ob, &dmd->map_object, IDWALK_NOP);
+ walk(userData, ob, &dmd->map_object, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -140,7 +140,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
DisplaceModifierData *dmd = (DisplaceModifierData *) md;
- walk(userData, ob, (ID **)&dmd->texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&dmd->texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index bde20e56748..05068b9b597 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -129,6 +129,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
/* add relation from canvases to all brush objects */
if (pmd && pmd->canvas) {
+#ifdef WITH_LEGACY_DEPSGRAPH
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");
@@ -137,6 +138,12 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
/* 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");
}
+#else
+ (void)forest;
+ (void)scene;
+ (void)ob;
+ (void)obNode;
+#endif
}
}
@@ -174,15 +181,15 @@ static void foreachIDLink(ModifierData *md, Object *ob,
DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- walk(userData, ob, (ID **)&surface->brush_group, IDWALK_NOP);
- walk(userData, ob, (ID **)&surface->init_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&surface->brush_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&surface->init_texture, IDWALK_CB_USER);
if (surface->effector_weights) {
- walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_CB_NOP);
}
}
}
if (pmd->brush) {
- walk(userData, ob, (ID **)&pmd->brush->mat, IDWALK_USER);
+ walk(userData, ob, (ID **)&pmd->brush->mat, IDWALK_CB_USER);
}
}
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 9186b10d8ca..56c494ff3c0 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -115,7 +115,7 @@ static void foreachObjectLink(
{
HookModifierData *hmd = (HookModifierData *) md;
- walk(userData, ob, &hmd->object, IDWALK_NOP);
+ walk(userData, ob, &hmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 7d4701e3ef2..dc246084dca 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -88,7 +88,7 @@ static void foreachObjectLink(
{
LatticeModifierData *lmd = (LatticeModifierData *) md;
- walk(userData, ob, &lmd->object, IDWALK_NOP);
+ walk(userData, ob, &lmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index 5e01a20d93b..dcc7fe4d4f1 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -74,7 +74,7 @@ static void foreachObjectLink(
ObjectWalkFunc walk, void *userData)
{
MaskModifierData *mmd = (MaskModifierData *)md;
- walk(userData, ob, &mmd->ob_arm, IDWALK_NOP);
+ walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 3f34319d25f..406ce398ee0 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -119,7 +119,7 @@ static void foreachObjectLink(
{
MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
- walk(userData, ob, &mmd->object, IDWALK_NOP);
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index 2f00a7c71b0..d956763fc1f 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -151,7 +151,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
- walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_USER);
+ walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_CB_USER);
}
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 88facb22e0e..dd127cc255c 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -72,7 +72,7 @@ static void foreachObjectLink(
{
MirrorModifierData *mmd = (MirrorModifierData *) md;
- walk(userData, ob, &mmd->mirror_ob, IDWALK_NOP);
+ walk(userData, ob, &mmd->mirror_ob, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 454c97451a8..20eae751ca4 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -501,7 +501,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
NormalEditModifierData *enmd = (NormalEditModifierData *) md;
- walk(userData, ob, &enmd->target, IDWALK_NOP);
+ walk(userData, ob, &enmd->target, IDWALK_CB_NOP);
}
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 4e78e758dc3..fbf5a958254 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -145,7 +145,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
{
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
- walk(userData, ob, &pimd->ob, IDWALK_NOP);
+ walk(userData, ob, &pimd->ob, IDWALK_CB_NOP);
}
static int particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p)
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 290e19736bb..87859cd240a 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -1093,7 +1093,7 @@ static void foreachObjectLink(
{
ScrewModifierData *ltmd = (ScrewModifierData *) md;
- walk(userData, ob, &ltmd->ob_axis, IDWALK_NOP);
+ walk(userData, ob, &ltmd->ob_axis, IDWALK_CB_NOP);
}
ModifierTypeInfo modifierType_Screw = {
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index 633311c2b87..a14747bc153 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -101,8 +101,8 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md;
- walk(userData, ob, &smd->target, IDWALK_NOP);
- walk(userData, ob, &smd->auxTarget, IDWALK_NOP);
+ walk(userData, ob, &smd->target, IDWALK_CB_NOP);
+ walk(userData, ob, &smd->auxTarget, IDWALK_CB_NOP);
}
static void deformVerts(ModifierData *md, Object *ob,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index c68f2651191..379eaea5b0c 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -290,7 +290,7 @@ static void foreachObjectLink(
ObjectWalkFunc walk, void *userData)
{
SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
- walk(userData, ob, &smd->origin, IDWALK_NOP);
+ walk(userData, ob, &smd->origin, IDWALK_CB_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index f04d7432a8f..c105a3ab3a7 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -138,10 +138,16 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
/* Actual code uses get_collisionobjects */
+#ifdef WITH_LEGACY_DEPSGRAPH
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");
-
dag_add_forcefield_relations(forest, scene, ob, obNode, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field");
+#else
+ (void)forest;
+ (void)scene;
+ (void)ob;
+ (void)obNode;
+#endif
}
}
@@ -168,17 +174,17 @@ static void foreachIDLink(ModifierData *md, Object *ob,
SmokeModifierData *smd = (SmokeModifierData *) md;
if (smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
- walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_NOP);
- walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_NOP);
- walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_CB_NOP);
if (smd->domain->effector_weights) {
- walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_CB_NOP);
}
}
if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) {
- walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_CB_USER);
}
}
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index 17adc7f1520..a0bbe5da04a 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -67,10 +67,17 @@ static void updateDepgraph(ModifierData *UNUSED(md), DagForest *forest,
Scene *scene, Object *ob, DagNode *obNode)
{
if (ob->soft) {
+#ifdef WITH_LEGACY_DEPSGRAPH
/* 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");
+#else
+ (void)forest;
+ (void)scene;
+ (void)ob;
+ (void)obNode;
+#endif
}
}
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index fb7668d16e0..78dc1ea8bcb 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -92,7 +92,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
int i;
for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i)
- walk(userData, ob, &umd->projectors[i], IDWALK_NOP);
+ walk(userData, ob, &umd->projectors[i], IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -100,7 +100,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
UVProjectModifierData *umd = (UVProjectModifierData *) md;
- walk(userData, ob, (ID **)&umd->image, IDWALK_USER);
+ walk(userData, ob, (ID **)&umd->image, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index 89994c3ae22..b3fc3842635 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -221,8 +221,8 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
UVWarpModifierData *umd = (UVWarpModifierData *) md;
- walk(userData, ob, &umd->object_dst, IDWALK_NOP);
- walk(userData, ob, &umd->object_src, IDWALK_NOP);
+ walk(userData, ob, &umd->object_dst, IDWALK_CB_NOP);
+ walk(userData, ob, &umd->object_src, IDWALK_CB_NOP);
}
static void uv_warp_deps_object_bone(DagForest *forest, DagNode *obNode,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index b38de140a91..92d44257d03 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -116,16 +116,16 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
WarpModifierData *wmd = (WarpModifierData *) md;
- walk(userData, ob, &wmd->object_from, IDWALK_NOP);
- walk(userData, ob, &wmd->object_to, IDWALK_NOP);
- walk(userData, ob, &wmd->map_object, IDWALK_NOP);
+ walk(userData, ob, &wmd->object_from, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->object_to, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WarpModifierData *wmd = (WarpModifierData *) md;
- walk(userData, ob, (ID **)&wmd->texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 683649ed1c0..f0c4940816e 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -111,8 +111,8 @@ static void foreachObjectLink(
{
WaveModifierData *wmd = (WaveModifierData *) md;
- walk(userData, ob, &wmd->objectcenter, IDWALK_NOP);
- walk(userData, ob, &wmd->map_object, IDWALK_NOP);
+ walk(userData, ob, &wmd->objectcenter, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -120,7 +120,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
WaveModifierData *wmd = (WaveModifierData *) md;
- walk(userData, ob, (ID **)&wmd->texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index 93567aed2c4..2a822ac07b5 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -126,14 +126,14 @@ static bool dependsOnTime(ModifierData *md)
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 170fbbed7f1..9bff7bf11f1 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -175,14 +175,14 @@ static bool dependsOnTime(ModifierData *md)
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index af59f11ba15..2c87838aeab 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -325,15 +325,15 @@ static bool dependsOnTime(ModifierData *md)
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- walk(userData, ob, &wmd->proximity_ob_target, IDWALK_NOP);
- walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
+ walk(userData, ob, &wmd->proximity_ob_target, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 171d5313c1d..a9c0df7d7e8 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -145,7 +145,7 @@ DefNode( CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBL
DefNode( CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
DefNode( CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
DefNode( CompositorNode, CMP_NODE_SETALPHA, 0, "SETALPHA", SetAlpha, "Set Alpha", "" )
-DefNode( CompositorNode, CMP_NODE_HUE_SAT, def_cmp_hue_saturation, "HUE_SAT", HueSat, "Hue Saturation Value","" )
+DefNode( CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue Saturation Value","" )
DefNode( CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" )
DefNode( CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" )
DefNode( CompositorNode, CMP_NODE_COMPOSITE, def_cmp_composite, "COMPOSITE", Composite, "Composite", "" )
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
index 1c31f4863ca..952ba78aff3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
+++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
@@ -35,8 +35,11 @@
/* **************** Hue Saturation ******************** */
static bNodeSocketTemplate cmp_node_hue_sat_in[] = {
- { SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Hue"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Saturation"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ -1, 0, "" }
};
static bNodeSocketTemplate cmp_node_hue_sat_out[] = {
@@ -44,23 +47,12 @@ static bNodeSocketTemplate cmp_node_hue_sat_out[] = {
{ -1, 0, "" }
};
-static void node_composit_init_hue_sat(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeHueSat *nhs = MEM_callocN(sizeof(NodeHueSat), "node hue sat");
- node->storage = nhs;
- nhs->hue = 0.5f;
- nhs->sat = 1.0f;
- nhs->val = 1.0f;
-}
-
void register_node_type_cmp_hue_sat(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, cmp_node_hue_sat_in, cmp_node_hue_sat_out);
- node_type_init(&ntype, node_composit_init_hue_sat);
- node_type_storage(&ntype, "NodeHueSat", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
index 7d1087435c2..6a96f1b30d8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
@@ -32,7 +32,7 @@
#include <string.h>
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
+#include "BLI_string_utils.h"
#include "BKE_context.h"
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.c b/source/blender/nodes/shader/nodes/node_shader_light_path.c
index b1001cd3937..052f2a66ec8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_light_path.c
+++ b/source/blender/nodes/shader/nodes/node_shader_light_path.c
@@ -39,6 +39,8 @@ static bNodeSocketTemplate sh_node_light_path_out[] = {
{ SOCK_FLOAT, 0, N_("Is Transmission Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Ray Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Ray Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Diffuse Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Glossy Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Transparent Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Transmission Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 1037c83815c..72705ffb3fb 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -263,7 +263,7 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
}
data_cb.id_curr = id;
- BKE_library_foreach_ID_link(id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_NOP);
+ BKE_library_foreach_ID_link(NULL, id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_CB_NOP);
if (data_cb.py_id_curr) {
Py_DECREF(data_cb.py_id_curr);
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index a357145ff39..903a65b20b7 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -3445,7 +3445,7 @@ bool RE_WriteRenderViewsMovie(
ok = mh->append_movie(movie_ctx_arr[0], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, (int *) ibuf_arr[2]->rect,
ibuf_arr[2]->x, ibuf_arr[2]->y, "", reports);
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < 3; i++) {
/* imbuf knows which rects are not part of ibuf */
IMB_freeImBuf(ibuf_arr[i]);
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index b9fd4d2e762..cef5e7e4a8e 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1846,7 +1846,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
BLENDER_VERSION / 100, BLENDER_VERSION % 100);
uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", url);
uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url",
- "http://www.blender.org/manual");
+ "https://docs.blender.org/manual/en/dev/");
uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org");
if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d"
@@ -3910,8 +3910,12 @@ static void previews_id_ensure(bContext *C, Scene *scene, ID *id)
}
}
-static int previews_id_ensure_callback(void *userdata, ID *UNUSED(self_id), ID **idptr, int UNUSED(cd_flag))
+static int previews_id_ensure_callback(void *userdata, ID *UNUSED(self_id), ID **idptr, int cb_flag)
{
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
PreviewsIDEnsureData *data = userdata;
ID *id = *idptr;
@@ -3944,7 +3948,7 @@ static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op))
preview_id_data.scene = scene;
id = (ID *)scene;
- BKE_library_foreach_ID_link(id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
+ BKE_library_foreach_ID_link(NULL, id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
}
/* Check a last time for ID not used (fake users only, in theory), and
@@ -4558,4 +4562,3 @@ EnumPropertyItem *RNA_mask_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA
{
return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->mask.first : NULL, true);
}
-
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 4eb72fb1619..27579e58dba 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -438,7 +438,7 @@ static void arg_py_context_restore(
* see: `doc/manpage/blender.1.py`
* - Parsed and extracted for the manual,
* which converts our ad-hoc formatting to reStructuredText.
- * see: http://www.blender.org/manual/advanced/command_line.html
+ * see: https://docs.blender.org/manual/en/dev/advanced/command_line.html
*
* \{ */
diff --git a/source/tools b/source/tools
-Subproject 896c5f78952adb2d091d28c65086d46992dabda
+Subproject b11375e89061303401376f7aeae42ac2fd64692
diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt
index a3860ce3e67..1d363f31119 100644
--- a/tests/gtests/CMakeLists.txt
+++ b/tests/gtests/CMakeLists.txt
@@ -4,6 +4,9 @@ if(WITH_GTESTS)
Include(GTestTesting)
+ add_definitions(${GFLAGS_DEFINES})
+ add_definitions(${GLOG_DEFINES})
+
# Otherwise we get warnings here that we cant fix in external projects
remove_strict_flags()
diff --git a/tests/gtests/blenlib/BLI_string_test.cc b/tests/gtests/blenlib/BLI_string_test.cc
index 17a4b5e82b9..08f2a745bdb 100644
--- a/tests/gtests/blenlib/BLI_string_test.cc
+++ b/tests/gtests/blenlib/BLI_string_test.cc
@@ -374,7 +374,7 @@ TEST(string, StrFormatIntGrouped)
const int word_num = BLI_string_find_split_words( \
word_str_src, word_str_src_len, ' ', word_info, word_cmp_size_input); \
EXPECT_EQ(word_num, word_cmp_size - 1); \
- EXPECT_EQ_ARRAY_ND(word_cmp, word_info, word_cmp_size, 2); \
+ EXPECT_EQ_ARRAY_ND<const int[2]>(word_cmp, word_info, word_cmp_size, 2); \
} ((void)0)
#define STRING_FIND_SPLIT_WORDS(word_str_src, ...) \
diff --git a/tests/gtests/testing/CMakeLists.txt b/tests/gtests/testing/CMakeLists.txt
index 1eb60e7f3b5..796f975ea65 100644
--- a/tests/gtests/testing/CMakeLists.txt
+++ b/tests/gtests/testing/CMakeLists.txt
@@ -47,7 +47,4 @@ set(SRC
testing.h
)
-add_definitions(${GFLAGS_DEFINES})
-add_definitions(${GLOG_DEFINES})
-
blender_add_lib(bf_testing_main "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index a29b612e0ef..4b5666e9b5a 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -399,24 +399,28 @@ endif()
if(WITH_CYCLES)
if(OPENIMAGEIO_IDIFF AND EXISTS "${TEST_SRC_DIR}/cycles/ctests/shader")
- add_test(cycles_reports_test
- ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
- -blender "${TEST_BLENDER_EXE_BARE}"
- -testdir "${TEST_SRC_DIR}/cycles/ctests/reports"
- -idiff "${OPENIMAGEIO_IDIFF}"
- )
- add_test(cycles_render_test
- ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
- -blender "${TEST_BLENDER_EXE_BARE}"
- -testdir "${TEST_SRC_DIR}/cycles/ctests/render"
- -idiff "${OPENIMAGEIO_IDIFF}"
- )
- add_test(cycles_shaders_test
- ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
- -blender "${TEST_BLENDER_EXE_BARE}"
- -testdir "${TEST_SRC_DIR}/cycles/ctests/shader"
- -idiff "${OPENIMAGEIO_IDIFF}"
- )
+ macro(add_cycles_render_test subject)
+ if(MSVC)
+ add_test(NAME cycles_${subject}_test
+ COMMAND
+ "$<TARGET_FILE_DIR:blender>/${BLENDER_VERSION_MAJOR}.${BLENDER_VERSION_MINOR}/python/bin/python$<$<CONFIG:Debug>:_d>"
+ ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
+ -blender "$<TARGET_FILE:blender>"
+ -testdir "${TEST_SRC_DIR}/cycles/ctests/${subject}"
+ -idiff "${OPENIMAGEIO_IDIFF}"
+ )
+ else()
+ add_test(cycles_${subject}_test
+ ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
+ -blender "${TEST_BLENDER_EXE_BARE}"
+ -testdir "${TEST_SRC_DIR}/cycles/ctests/${subject}"
+ -idiff "${OPENIMAGEIO_IDIFF}"
+ )
+ endif()
+ endmacro()
+ add_cycles_render_test(reports)
+ add_cycles_render_test(render)
+ add_cycles_render_test(shader)
else()
MESSAGE(STATUS "Disabling Cycles tests because tests folder does not exist")
endif()
diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py
index 78b4b346f24..ae8848570f0 100755
--- a/tests/python/cycles_render_tests.py
+++ b/tests/python/cycles_render_tests.py
@@ -6,9 +6,46 @@ import os
import shutil
import subprocess
import sys
+import time
import tempfile
+class COLORS_ANSI:
+ RED = '\033[00;31m'
+ GREEN = '\033[00;32m'
+ ENDC = '\033[0m'
+
+
+class COLORS_DUMMY:
+ RED = ''
+ GREEN = ''
+ ENDC = ''
+
+COLORS = COLORS_DUMMY
+
+
+def printMessage(type, status, message):
+ if type == 'SUCCESS':
+ print(COLORS.GREEN, end="")
+ elif type == 'FAILURE':
+ print(COLORS.RED, end="")
+ status_text = ...
+ if status == 'RUN':
+ status_text = " RUN "
+ elif status == 'OK':
+ status_text = " OK "
+ elif status == 'PASSED':
+ status_text = " PASSED "
+ elif status == 'FAILED':
+ status_text = " FAILED "
+ else:
+ status_text = status
+ print("[{}]" . format(status_text), end="")
+ print(COLORS.ENDC, end="")
+ print(" {}" . format(message))
+ sys.stdout.flush()
+
+
def render_file(filepath):
command = (
BLENDER,
@@ -83,16 +120,32 @@ def verify_output(filepath):
def run_test(filepath):
testname = test_get_name(filepath)
spacer = "." * (32 - len(testname))
- print(testname, spacer, end="")
- sys.stdout.flush()
+ printMessage('SUCCESS', 'RUN', testname)
+ time_start = time.time()
error = render_file(filepath)
+ status = "FAIL"
if not error:
- if verify_output(filepath):
- print("PASS")
- else:
+ if not verify_output(filepath):
error = "VERIFY"
- if error:
- print("FAIL", error)
+ time_end = time.time()
+ elapsed_ms = int((time_end - time_start) * 1000)
+ if not error:
+ printMessage('SUCCESS', 'OK', "{} ({} ms)" .
+ format(testname, elapsed_ms))
+ else:
+ if error == "NO_CYCLES":
+ print("Can't perform tests because Cycles failed to load!")
+ return False
+ elif error == "NO_START":
+ print('Can not perform tests because blender fails to start.',
+ 'Make sure INSTALL target was run.')
+ return False
+ elif error == 'VERIFY':
+ print("Rendered result is different from reference image")
+ else:
+ print("Unknown error %r" % error)
+ printMessage('FAILURE', 'FAILED', "{} ({} ms)" .
+ format(testname, elapsed_ms))
return error
@@ -105,30 +158,38 @@ def blend_list(path):
def run_all_tests(dirpath):
+ passed_tests = []
failed_tests = []
all_files = list(blend_list(dirpath))
all_files.sort()
+ printMessage('SUCCESS', "==========",
+ "Running {} tests from 1 test case." . format(len(all_files)))
+ time_start = time.time()
for filepath in all_files:
error = run_test(filepath)
+ testname = test_get_name(filepath)
if error:
if error == "NO_CYCLES":
- print("Can't perform tests because Cycles failed to load!")
return False
elif error == "NO_START":
- print('Can not perform tests because blender fails to start.',
- 'Make sure INSTALL target was run.')
return False
- elif error == 'VERIFY':
- pass
- else:
- print("Unknown error %r" % error)
- testname = test_get_name(filepath)
failed_tests.append(testname)
+ else:
+ passed_tests.append(testname)
+ time_end = time.time()
+ elapsed_ms = int((time_end - time_start) * 1000)
+ print("")
+ printMessage('SUCCESS', "==========",
+ "{} tests from 1 test case ran. ({} ms total)" .
+ format(len(all_files), elapsed_ms))
+ printMessage('SUCCESS', 'PASSED', "{} tests." .
+ format(len(passed_tests)))
if failed_tests:
+ printMessage('FAILURE', 'FAILED', "{} tests, listed below:" .
+ format(len(failed_tests)))
failed_tests.sort()
- print("\n\nFAILED tests:")
for test in failed_tests:
- print(" ", test)
+ printMessage('FAILURE', "FAILED", "{}" . format(test))
return False
return True
@@ -145,10 +206,14 @@ def main():
parser = create_argparse()
args = parser.parse_args()
+ global COLORS
global BLENDER, ROOT, IDIFF
global TEMP_FILE, TEMP_FILE_MASK, TEST_SCRIPT
global VERBOSE
+ if os.environ.get("CYCLESTEST_COLOR") is not None:
+ COLORS = COLORS_ANSI
+
BLENDER = args.blender[0]
ROOT = args.testdir[0]
IDIFF = args.idiff[0]