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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt37
-rw-r--r--GNUmakefile50
-rw-r--r--build_files/build_environment/cmake/openimagedenoise.cmake2
-rw-r--r--build_files/build_environment/cmake/opensubdiv.cmake2
-rw-r--r--build_files/build_environment/cmake/tbb.cmake18
-rw-r--r--build_files/build_environment/cmake/usd.cmake4
-rw-r--r--build_files/build_environment/patches/cmakelists_tbb.txt9
-rw-r--r--build_files/build_environment/patches/openimagedenoise.diff11
-rw-r--r--build_files/cmake/Modules/GTestTesting.cmake3
-rw-r--r--build_files/cmake/macros.cmake8
-rw-r--r--build_files/cmake/platform/platform_unix.cmake35
-rw-r--r--build_files/cmake/platform/platform_win32.cmake50
-rw-r--r--build_files/windows/configure_msbuild.cmd5
-rw-r--r--build_files/windows/configure_ninja.cmd7
-rw-r--r--build_files/windows/parse_arguments.cmd2
-rw-r--r--build_files/windows/reset_variables.cmd1
-rw-r--r--doc/doxygen/Doxyfile2
-rw-r--r--extern/CMakeLists.txt2
-rw-r--r--extern/audaspace/bindings/C/AUD_Device.cpp4
-rw-r--r--extern/audaspace/bindings/C/AUD_Device.h4
-rw-r--r--extern/audaspace/bindings/C/AUD_DynamicMusic.cpp6
-rw-r--r--extern/audaspace/bindings/C/AUD_DynamicMusic.h6
-rw-r--r--extern/audaspace/bindings/C/AUD_Handle.cpp4
-rw-r--r--extern/audaspace/bindings/C/AUD_Handle.h4
-rw-r--r--extern/audaspace/bindings/C/AUD_Sequence.cpp4
-rw-r--r--extern/audaspace/bindings/C/AUD_Sequence.h4
-rw-r--r--extern/audaspace/bindings/C/AUD_Special.cpp4
-rw-r--r--extern/audaspace/bindings/C/AUD_Special.h4
-rw-r--r--extern/audaspace/bindings/doc/device.rst1
-rw-r--r--extern/audaspace/bindings/doc/handle.rst1
-rw-r--r--extern/audaspace/bindings/doc/index.rst3
-rw-r--r--extern/audaspace/bindings/doc/sequence.rst1
-rw-r--r--extern/audaspace/bindings/doc/sequence_entry.rst1
-rw-r--r--extern/audaspace/bindings/doc/sound.rst1
-rw-r--r--extern/audaspace/bindings/doc/tutorials.rst2
-rw-r--r--extern/audaspace/bindings/python/PyDynamicMusic.cpp6
-rw-r--r--extern/audaspace/bindings/python/PyHandle.cpp6
-rw-r--r--extern/audaspace/bindings/python/PySequence.cpp14
-rw-r--r--extern/audaspace/bindings/python/PySequenceEntry.cpp10
-rw-r--r--extern/audaspace/bindings/python/PySound.cpp9
-rw-r--r--extern/audaspace/include/devices/DefaultSynchronizer.h4
-rw-r--r--extern/audaspace/include/devices/IDeviceFactory.h3
-rw-r--r--extern/audaspace/include/devices/IHandle.h4
-rw-r--r--extern/audaspace/include/devices/ISynchronizer.h4
-rw-r--r--extern/audaspace/include/devices/NULLDevice.h4
-rw-r--r--extern/audaspace/include/devices/SoftwareDevice.h4
-rw-r--r--extern/audaspace/include/file/IFileInput.h5
-rw-r--r--extern/audaspace/include/fx/Delay.h6
-rw-r--r--extern/audaspace/include/fx/DelayReader.h2
-rw-r--r--extern/audaspace/include/fx/DynamicMusic.h10
-rw-r--r--extern/audaspace/include/fx/Fader.h10
-rw-r--r--extern/audaspace/include/fx/FaderReader.h6
-rw-r--r--extern/audaspace/include/fx/Limiter.h10
-rw-r--r--extern/audaspace/include/fx/LimiterReader.h6
-rw-r--r--extern/audaspace/include/sequence/Sequence.h2
-rw-r--r--extern/audaspace/include/sequence/SequenceData.h2
-rw-r--r--extern/audaspace/include/sequence/SequenceEntry.h10
-rw-r--r--extern/audaspace/plugins/jack/JackDevice.cpp6
-rw-r--r--extern/audaspace/plugins/jack/JackDevice.h4
-rw-r--r--extern/audaspace/plugins/jack/JackSynchronizer.cpp4
-rw-r--r--extern/audaspace/plugins/jack/JackSynchronizer.h4
-rw-r--r--extern/audaspace/plugins/openal/OpenALDevice.cpp4
-rw-r--r--extern/audaspace/plugins/openal/OpenALDevice.h4
-rw-r--r--extern/audaspace/src/devices/DefaultSynchronizer.cpp4
-rw-r--r--extern/audaspace/src/devices/NULLDevice.cpp4
-rw-r--r--extern/audaspace/src/devices/SoftwareDevice.cpp6
-rw-r--r--extern/audaspace/src/fx/Delay.cpp4
-rw-r--r--extern/audaspace/src/fx/DelayReader.cpp2
-rw-r--r--extern/audaspace/src/fx/DynamicMusic.cpp10
-rw-r--r--extern/audaspace/src/fx/Fader.cpp6
-rw-r--r--extern/audaspace/src/fx/FaderReader.cpp8
-rw-r--r--extern/audaspace/src/fx/Limiter.cpp6
-rw-r--r--extern/audaspace/src/fx/LimiterReader.cpp2
-rw-r--r--extern/audaspace/src/respec/ChannelMapperReader.cpp2
-rw-r--r--extern/audaspace/src/respec/Mixer.cpp4
-rw-r--r--extern/audaspace/src/sequence/Sequence.cpp2
-rw-r--r--extern/audaspace/src/sequence/SequenceData.cpp2
-rw-r--r--extern/audaspace/src/sequence/SequenceEntry.cpp4
-rw-r--r--extern/audaspace/src/sequence/SequenceHandle.cpp8
-rw-r--r--extern/audaspace/src/sequence/SequenceHandle.h6
-rw-r--r--extern/audaspace/src/sequence/SequenceReader.cpp7
-rw-r--r--extern/mantaflow/preprocessed/gitinfo.h2
-rw-r--r--extern/mantaflow/preprocessed/plugin/extforces.cpp28
-rw-r--r--intern/CMakeLists.txt1
-rw-r--r--intern/cycles/blender/addon/ui.py252
-rw-r--r--intern/dualcon/dualcon.h2
-rw-r--r--intern/dualcon/intern/octree.cpp2
-rw-r--r--intern/ghost/CMakeLists.txt180
-rw-r--r--intern/ghost/GHOST_IContext.h1
-rw-r--r--intern/ghost/GHOST_ISystem.h4
-rw-r--r--intern/ghost/GHOST_IWindow.h8
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp11
-rw-r--r--intern/ghost/intern/GHOST_Debug.h18
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerWin32.cpp12
-rw-r--r--intern/ghost/intern/GHOST_DropTargetWin32.cpp24
-rw-r--r--intern/ghost/intern/GHOST_EventKey.h2
-rw-r--r--intern/ghost/intern/GHOST_EventPrinter.h2
-rw-r--r--intern/ghost/intern/GHOST_ISystem.cpp57
-rw-r--r--intern/ghost/intern/GHOST_IXrGraphicsBinding.h2
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp2
-rw-r--r--intern/ghost/intern/GHOST_System.cpp6
-rw-r--r--intern/ghost/intern/GHOST_System.h8
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm2
-rw-r--r--intern/ghost/intern/GHOST_SystemNULL.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp1654
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h111
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp8
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h2
-rw-r--r--intern/ghost/intern/GHOST_Window.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h8
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm9
-rw-r--r--intern/ghost/intern/GHOST_WindowNULL.h9
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.cpp10
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.h7
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp406
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.h121
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp15
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h8
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp19
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h7
-rw-r--r--intern/ghost/intern/GHOST_XrGraphicsBinding.cpp6
-rw-r--r--intern/ghost/intern/GHOST_Xr_openxr_includes.h2
-rw-r--r--intern/ghost/test/CMakeLists.txt3
-rw-r--r--intern/ghost/test/gears/GHOST_Test.cpp11
-rw-r--r--intern/libmv/intern/camera_intrinsics.cc53
-rw-r--r--intern/libmv/intern/camera_intrinsics.h4
-rw-r--r--intern/libmv/libmv/simple_pipeline/bundle.cc527
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc63
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics.h58
-rw-r--r--intern/libmv/libmv/simple_pipeline/distortion_models.cc92
-rw-r--r--intern/libmv/libmv/simple_pipeline/distortion_models.h78
-rw-r--r--intern/mantaflow/intern/MANTA_main.cpp1669
-rw-r--r--intern/mantaflow/intern/MANTA_main.h109
-rw-r--r--intern/mantaflow/intern/strings/fluid_script.h54
-rw-r--r--intern/mantaflow/intern/strings/liquid_script.h8
-rw-r--r--intern/mantaflow/intern/strings/smoke_script.h4
-rw-r--r--intern/string/STR_String.h366
-rw-r--r--intern/string/intern/STR_String.cpp637
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c6
m---------release/scripts/addons0
-rw-r--r--release/scripts/modules/rna_keymap_ui.py7
-rw-r--r--release/scripts/presets/interface_theme/blender_light.xml2
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py24
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py12
-rw-r--r--release/scripts/startup/bl_operators/__init__.py1
-rw-r--r--release/scripts/startup/bl_operators/simulation.py39
-rw-r--r--release/scripts/startup/bl_operators/userpref.py36
-rw-r--r--release/scripts/startup/bl_operators/view3d.py23
-rw-r--r--release/scripts/startup/bl_operators/wm.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_data_armature.py7
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py44
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_data_empty.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py42
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py38
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py36
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py5
-rw-r--r--release/scripts/startup/bl_ui/properties_object.py67
-rw-r--r--release/scripts/startup/bl_ui/properties_output.py57
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py30
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py39
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py33
-rw-r--r--release/scripts/startup/bl_ui/properties_texture.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_view_layer.py53
-rw-r--r--release/scripts/startup/bl_ui/properties_world.py4
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py4
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py5
-rw-r--r--release/scripts/startup/bl_ui/space_image.py5
-rw-r--r--release/scripts/startup/bl_ui/space_node.py8
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py6
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py90
-rw-r--r--release/scripts/startup/bl_ui/space_text.py21
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py19
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py7
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py321
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py62
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py117
-rw-r--r--release/scripts/startup/nodeitems_builtins.py74
-rw-r--r--source/blender/blenfont/BLF_api.h6
-rw-r--r--source/blender/blenfont/intern/blf.c4
-rw-r--r--source/blender/blenfont/intern/blf_font.c40
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c78
-rw-r--r--source/blender/blenfont/intern/blf_internal.h6
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h16
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c4
-rw-r--r--source/blender/blenkernel/BKE_animsys.h6
-rw-r--r--source/blender/blenkernel/BKE_armature.h2
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_curve.h2
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h63
-rw-r--r--source/blender/blenkernel/BKE_fcurve_driver.h106
-rw-r--r--source/blender/blenkernel/BKE_idtype.h1
-rw-r--r--source/blender/blenkernel/BKE_image.h2
-rw-r--r--source/blender/blenkernel/BKE_main.h3
-rw-r--r--source/blender/blenkernel/BKE_modifier.h36
-rw-r--r--source/blender/blenkernel/BKE_multires.h23
-rw-r--r--source/blender/blenkernel/BKE_node.h38
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h23
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h14
-rw-r--r--source/blender/blenkernel/BKE_simulation.h33
-rw-r--r--source/blender/blenkernel/BKE_sound.h6
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h6
-rw-r--r--source/blender/blenkernel/BKE_tracking.h14
-rw-r--r--source/blender/blenkernel/CMakeLists.txt8
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c23
-rw-r--r--source/blender/blenkernel/intern/action.c2
-rw-r--r--source/blender/blenkernel/intern/anim_data.c8
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c26
-rw-r--r--source/blender/blenkernel/intern/blendfile.c3
-rw-r--r--source/blender/blenkernel/intern/brush.c26
-rw-r--r--source/blender/blenkernel/intern/colortools.c69
-rw-r--r--source/blender/blenkernel/intern/constraint.c8
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c2
-rw-r--r--source/blender/blenkernel/intern/curve.c14
-rw-r--r--source/blender/blenkernel/intern/displist.c18
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c33
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c7
-rw-r--r--source/blender/blenkernel/intern/fcurve.c1963
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c1294
-rw-r--r--source/blender/blenkernel/intern/fluid.c56
-rw-r--r--source/blender/blenkernel/intern/hair.c61
-rw-r--r--source/blender/blenkernel/intern/idtype.c5
-rw-r--r--source/blender/blenkernel/intern/image.c4
-rw-r--r--source/blender/blenkernel/intern/ipo.c1
-rw-r--r--source/blender/blenkernel/intern/lattice.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id.c63
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c62
-rw-r--r--source/blender/blenkernel/intern/lib_query.c95
-rw-r--r--source/blender/blenkernel/intern/light.c2
-rw-r--r--source/blender/blenkernel/intern/linestyle.c2
-rw-r--r--source/blender/blenkernel/intern/main.c3
-rw-r--r--source/blender/blenkernel/intern/material.c4
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c10
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c8
-rw-r--r--source/blender/blenkernel/intern/modifier.c8
-rw-r--r--source/blender/blenkernel/intern/movieclip.c8
-rw-r--r--source/blender/blenkernel/intern/multires.c22
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c76
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.h31
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c146
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_subdivide.c106
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_util.c90
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.c1297
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.h94
-rw-r--r--source/blender/blenkernel/intern/node.c161
-rw-r--r--source/blender/blenkernel/intern/object.c42
-rw-r--r--source/blender/blenkernel/intern/ocean.c51
-rw-r--r--source/blender/blenkernel/intern/paint.c4
-rw-r--r--source/blender/blenkernel/intern/particle.c13
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c12
-rw-r--r--source/blender/blenkernel/intern/particle_system.c17
-rw-r--r--source/blender/blenkernel/intern/pbvh.c28
-rw-r--r--source/blender/blenkernel/intern/pointcloud.c63
-rw-r--r--source/blender/blenkernel/intern/scene.c2
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c70
-rw-r--r--source/blender/blenkernel/intern/seqprefetch.c3
-rw-r--r--source/blender/blenkernel/intern/sequencer.c69
-rw-r--r--source/blender/blenkernel/intern/simulation.cc110
-rw-r--r--source/blender/blenkernel/intern/sound.c16
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c82
-rw-r--r--source/blender/blenkernel/intern/subdiv_deform.c40
-rw-r--r--source/blender/blenkernel/intern/subdiv_foreach.c86
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c120
-rw-r--r--source/blender/blenkernel/intern/texture.c2
-rw-r--r--source/blender/blenkernel/intern/tracking.c28
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c12
-rw-r--r--source/blender/blenkernel/intern/volume.cc48
-rw-r--r--source/blender/blenkernel/intern/world.c2
-rw-r--r--source/blender/blenlib/BLI_allocator.hh (renamed from source/blender/blenlib/BLI_allocator.h)6
-rw-r--r--source/blender/blenlib/BLI_array.hh (renamed from source/blender/blenlib/BLI_array_cxx.h)28
-rw-r--r--source/blender/blenlib/BLI_array_ref.hh (renamed from source/blender/blenlib/BLI_array_ref.h)10
-rw-r--r--source/blender/blenlib/BLI_color.hh92
-rw-r--r--source/blender/blenlib/BLI_dot_export.hh290
-rw-r--r--source/blender/blenlib/BLI_dot_export_attribute_enums.hh125
-rw-r--r--source/blender/blenlib/BLI_float2.hh86
-rw-r--r--source/blender/blenlib/BLI_float3.hh218
-rw-r--r--source/blender/blenlib/BLI_float4x4.hh115
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h2
-rw-r--r--source/blender/blenlib/BLI_hash.h2
-rw-r--r--source/blender/blenlib/BLI_hash.hh (renamed from source/blender/blenlib/BLI_hash_cxx.h)36
-rw-r--r--source/blender/blenlib/BLI_index_range.hh (renamed from source/blender/blenlib/BLI_index_range.h)6
-rw-r--r--source/blender/blenlib/BLI_lasso_2d.h10
-rw-r--r--source/blender/blenlib/BLI_linear_allocator.hh173
-rw-r--r--source/blender/blenlib/BLI_listbase_wrapper.hh (renamed from source/blender/blenlib/BLI_listbase_wrapper.h)12
-rw-r--r--source/blender/blenlib/BLI_map.hh (renamed from source/blender/blenlib/BLI_map.h)68
-rw-r--r--source/blender/blenlib/BLI_math_vector.h5
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh (renamed from source/blender/blenlib/BLI_memory_utils_cxx.h)6
-rw-r--r--source/blender/blenlib/BLI_open_addressing.hh (renamed from source/blender/blenlib/BLI_open_addressing.h)185
-rw-r--r--source/blender/blenlib/BLI_optional.hh (renamed from source/blender/blenlib/BLI_optional.h)8
-rw-r--r--source/blender/blenlib/BLI_set.hh (renamed from source/blender/blenlib/BLI_set.h)49
-rw-r--r--source/blender/blenlib/BLI_stack.hh (renamed from source/blender/blenlib/BLI_stack_cxx.h)13
-rw-r--r--source/blender/blenlib/BLI_string_map.hh (renamed from source/blender/blenlib/BLI_string_map.h)85
-rw-r--r--source/blender/blenlib/BLI_string_ref.hh (renamed from source/blender/blenlib/BLI_string_ref.h)26
-rw-r--r--source/blender/blenlib/BLI_system.h4
-rw-r--r--source/blender/blenlib/BLI_task.h100
-rw-r--r--source/blender/blenlib/BLI_threads.h2
-rw-r--r--source/blender/blenlib/BLI_timeit.hh62
-rw-r--r--source/blender/blenlib/BLI_utility_mixins.hh (renamed from source/blender/blenlib/BLI_utility_mixins.h)6
-rw-r--r--source/blender/blenlib/BLI_vector.hh (renamed from source/blender/blenlib/BLI_vector.h)56
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh (renamed from source/blender/blenlib/BLI_vector_set.h)120
-rw-r--r--source/blender/blenlib/CMakeLists.txt58
-rw-r--r--source/blender/blenlib/intern/BLI_index_range.cc8
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c1
-rw-r--r--source/blender/blenlib/intern/dot_export.cc305
-rw-r--r--source/blender/blenlib/intern/lasso_2d.c48
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c21
-rw-r--r--source/blender/blenlib/intern/system.c52
-rw-r--r--source/blender/blenlib/intern/system_win32.c378
-rw-r--r--source/blender/blenlib/intern/task_iterator.c558
-rw-r--r--source/blender/blenlib/intern/task_pool.cc1149
-rw-r--r--source/blender/blenlib/intern/task_range.cc (renamed from source/blender/blenkernel/intern/pbvh_parallel.cc)103
-rw-r--r--source/blender/blenlib/intern/task_scheduler.cc73
-rw-r--r--source/blender/blenlib/intern/threads.c26
-rw-r--r--source/blender/blenlib/intern/timeit.cc36
-rw-r--r--source/blender/blenloader/CMakeLists.txt1
-rw-r--r--source/blender/blenloader/intern/readfile.c155
-rw-r--r--source/blender/blenloader/intern/readfile.h1
-rw-r--r--source/blender/blenloader/intern/versioning_270.c2
-rw-r--r--source/blender/blenloader/intern/versioning_280.c1
-rw-r--r--source/blender/blenloader/intern/versioning_290.c66
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c3
-rw-r--r--source/blender/blenloader/intern/writefile.c33
-rw-r--r--source/blender/blentranslation/BLT_translation.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c1
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c65
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c12
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cpp3
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc56
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h5
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc73
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h14
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc42
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc43
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.h3
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc21
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc11
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc23
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h8
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc3
-rw-r--r--source/blender/depsgraph/intern/depsgraph_physics.cc61
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc11
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc75
-rw-r--r--source/blender/depsgraph/intern/depsgraph_registry.cc35
-rw-r--r--source/blender/depsgraph/intern/depsgraph_registry.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_relation.cc14
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type.h16
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc60
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc18
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_stats.cc4
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.cc67
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h20
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.cc51
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.h18
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc1
-rw-r--r--source/blender/draw/DRW_engine.h2
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c3
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c10
-rw-r--r--source/blender/draw/intern/draw_manager.c10
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c4
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c79
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c15
-rw-r--r--source/blender/editors/animation/anim_filter.c14
-rw-r--r--source/blender/editors/animation/drivers.c1
-rw-r--r--source/blender/editors/animation/keyframes_edit.c2
-rw-r--r--source/blender/editors/animation/keyframing.c1
-rw-r--r--source/blender/editors/armature/armature_relations.c2
-rw-r--r--source/blender/editors/armature/pose_slide.c77
-rw-r--r--source/blender/editors/armature/pose_transform.c2
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c204
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c52
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c14
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h7
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c14
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c34
-rw-r--r--source/blender/editors/include/ED_anim_api.h3
-rw-r--r--source/blender/editors/include/ED_image.h14
-rw-r--r--source/blender/editors/include/ED_info.h6
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h4
-rw-r--r--source/blender/editors/include/ED_node.h6
-rw-r--r--source/blender/editors/include/ED_outliner.h2
-rw-r--r--source/blender/editors/include/ED_particle.h2
-rw-r--r--source/blender/editors/include/ED_transform.h2
-rw-r--r--source/blender/editors/include/UI_interface.h36
-rw-r--r--source/blender/editors/include/UI_view2d.h23
-rw-r--r--source/blender/editors/interface/interface.c36
-rw-r--r--source/blender/editors/interface/interface_anim.c56
-rw-r--r--source/blender/editors/interface/interface_handlers.c80
-rw-r--r--source/blender/editors/interface/interface_icons.c3
-rw-r--r--source/blender/editors/interface/interface_intern.h7
-rw-r--r--source/blender/editors/interface/interface_layout.c353
-rw-r--r--source/blender/editors/interface/interface_panel.c43
-rw-r--r--source/blender/editors/interface/interface_templates.c501
-rw-r--r--source/blender/editors/interface/interface_utils.c16
-rw-r--r--source/blender/editors/interface/interface_widgets.c134
-rw-r--r--source/blender/editors/interface/view2d.c98
-rw-r--r--source/blender/editors/mask/mask_select.c18
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c18
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c8
-rw-r--r--source/blender/editors/mesh/mesh_ops.c12
-rw-r--r--source/blender/editors/object/CMakeLists.txt3
-rw-r--r--source/blender/editors/object/object_edit.c192
-rw-r--r--source/blender/editors/object/object_intern.h2
-rw-r--r--source/blender/editors/object/object_modifier.c151
-rw-r--r--source/blender/editors/object/object_ops.c2
-rw-r--r--source/blender/editors/object/object_transform.c22
-rw-r--r--source/blender/editors/physics/particle_edit.c39
-rw-r--r--source/blender/editors/physics/physics_fluid.c4
-rw-r--r--source/blender/editors/render/render_opengl.c20
-rw-r--r--source/blender/editors/screen/area.c21
-rw-r--r--source/blender/editors/screen/screen_ops.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c26
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c28
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c214
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c15
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c15
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c10
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c31
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/space_action/action_select.c8
-rw-r--r--source/blender/editors/space_clip/clip_draw.c63
-rw-r--r--source/blender/editors/space_clip/clip_editor.c13
-rw-r--r--source/blender/editors/space_clip/clip_ops.c9
-rw-r--r--source/blender/editors/space_clip/clip_utils.c3
-rw-r--r--source/blender/editors/space_clip/tracking_select.c22
-rw-r--r--source/blender/editors/space_file/filelist.c14
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c1
-rw-r--r--source/blender/editors/space_graph/graph_select.c8
-rw-r--r--source/blender/editors/space_image/image_edit.c11
-rw-r--r--source/blender/editors/space_image/space_image.c1
-rw-r--r--source/blender/editors/space_info/info_stats.c304
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c29
-rw-r--r--source/blender/editors/space_nla/nla_channels.c3
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_node/drawnode.c950
-rw-r--r--source/blender/editors/space_node/node_buttons.c2
-rw-r--r--source/blender/editors/space_node/node_draw.c262
-rw-r--r--source/blender/editors/space_node/node_edit.c6
-rw-r--r--source/blender/editors/space_node/node_group.c9
-rw-r--r--source/blender/editors/space_node/node_intern.h14
-rw-r--r--source/blender/editors/space_node/node_select.c19
-rw-r--r--source/blender/editors/space_node/node_templates.c118
-rw-r--r--source/blender/editors/space_node/space_node.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c38
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c200
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h11
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c3
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c210
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c10
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c20
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c24
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c214
-rw-r--r--source/blender/editors/transform/transform.c198
-rw-r--r--source/blender/editors/transform/transform.h28
-rw-r--r--source/blender/editors/transform/transform_constraints.c26
-rw-r--r--source/blender/editors/transform/transform_constraints.h2
-rw-r--r--source/blender/editors/transform/transform_convert.c32
-rw-r--r--source/blender/editors/transform/transform_convert.h8
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c10
-rw-r--r--source/blender/editors/transform/transform_generics.c151
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c4
-rw-r--r--source/blender/editors/transform/transform_mode.c2
-rw-r--r--source/blender/editors/transform/transform_mode_edge_rotate_normal.c2
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c2
-rw-r--r--source/blender/editors/transform/transform_mode_shear.c12
-rw-r--r--source/blender/editors/transform/transform_ops.c11
-rw-r--r--source/blender/editors/transform/transform_orientations.c52
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt1
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c33
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h28
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c3233
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c3415
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c165
-rw-r--r--source/blender/gpu/GPU_immediate_util.h7
-rw-r--r--source/blender/gpu/GPU_shader.h2
-rw-r--r--source/blender/gpu/intern/gpu_immediate.c8
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c26
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.c6
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c8
-rw-r--r--source/blender/imbuf/intern/imageprocess.c16
-rw-r--r--source/blender/makesdna/DNA_ID.h9
-rw-r--r--source/blender/makesdna/DNA_armature_types.h18
-rw-r--r--source/blender/makesdna/DNA_brush_types.h4
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h36
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h48
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h1
-rw-r--r--source/blender/makesdna/DNA_layer_types.h1
-rw-r--r--source/blender/makesdna/DNA_material_types.h20
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h32
-rw-r--r--source/blender/makesdna/DNA_node_types.h44
-rw-r--r--source/blender/makesdna/DNA_object_force_types.h1
-rw-r--r--source/blender/makesdna/DNA_object_types.h1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h42
-rw-r--r--source/blender/makesdna/DNA_screen_types.h4
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h3
-rw-r--r--source/blender/makesdna/DNA_shader_fx_types.h1
-rw-r--r--source/blender/makesdna/DNA_simulation_defaults.h40
-rw-r--r--source/blender/makesdna/DNA_simulation_types.h41
-rw-r--r--source/blender/makesdna/DNA_space_types.h6
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h4
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h7
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h1
-rw-r--r--source/blender/makesdna/DNA_volume_types.h6
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt1
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c8
-rw-r--r--source/blender/makesdna/intern/makesdna.c2
-rw-r--r--source/blender/makesrna/RNA_access.h8
-rw-r--r--source/blender/makesrna/RNA_enum_types.h10
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt12
-rw-r--r--source/blender/makesrna/intern/makesrna.c3
-rw-r--r--source/blender/makesrna/intern/rna_ID.c14
-rw-r--r--source/blender/makesrna/intern/rna_access.c117
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c1
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c2
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c2
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c144
-rw-r--r--source/blender/makesrna/intern/rna_internal.h2
-rw-r--r--source/blender/makesrna/intern/rna_main.c11
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c57
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c4
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c418
-rw-r--r--source/blender/makesrna/intern/rna_object.c1
-rw-r--r--source/blender/makesrna/intern/rna_scene.c24
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c14
-rw-r--r--source/blender/makesrna/intern/rna_simulation.c56
-rw-r--r--source/blender/makesrna/intern/rna_space.c66
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c14
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c31
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c4
-rw-r--r--source/blender/makesrna/intern/rna_xr.c16
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c7
-rw-r--r--source/blender/modifiers/intern/MOD_array.c7
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c7
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c7
-rw-r--r--source/blender/modifiers/intern/MOD_build.c7
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c7
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c5
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c5
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c5
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c7
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c10
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c7
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c5
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c7
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c7
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c7
-rw-r--r--source/blender/modifiers/intern/MOD_fluid.c7
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c7
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c5
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c5
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c7
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc17
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c7
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c7
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c7
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c7
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c7
-rw-r--r--source/blender/modifiers/intern/MOD_none.c5
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c7
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c7
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c7
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c5
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c13
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c7
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c7
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c7
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c7
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c7
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c5
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c7
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c11
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c4
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c6
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_util.h12
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c7
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c5
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c7
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c7
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c7
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c7
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c7
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c7
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c7
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c7
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c7
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c7
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c7
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c9
-rw-r--r--source/blender/nodes/CMakeLists.txt29
-rw-r--r--source/blender/nodes/NOD_common.h8
-rw-r--r--source/blender/nodes/NOD_function.h34
-rw-r--r--source/blender/nodes/NOD_simulation.h47
-rw-r--r--source/blender/nodes/NOD_static_types.h20
-rw-r--r--source/blender/nodes/function/node_function_util.cc30
-rw-r--r--source/blender/nodes/function/node_function_util.h40
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc62
-rw-r--r--source/blender/nodes/function/nodes/node_fn_combine_strings.cc21
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_compare.cc66
-rw-r--r--source/blender/nodes/function/nodes/node_fn_group_instance_id.cc15
-rw-r--r--source/blender/nodes/function/nodes/node_fn_switch.cc76
-rw-r--r--source/blender/nodes/intern/node_common.h8
-rw-r--r--source/blender/nodes/intern/node_socket.c54
-rw-r--r--source/blender/nodes/intern/node_util.h8
-rw-r--r--source/blender/nodes/shader/node_shader_util.c11
-rw-r--r--source/blender/nodes/shader/node_shader_util.h2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.c2
-rw-r--r--source/blender/nodes/simulation/node_simulation_tree.cc45
-rw-r--r--source/blender/nodes/simulation/node_simulation_util.cc29
-rw-r--r--source/blender/nodes/simulation/node_simulation_util.h40
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_common.cc45
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_emit_particles.cc38
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_execute_condition.cc39
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_force.cc36
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_multi_execute.cc38
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_attribute.cc52
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_birth_event.cc37
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_mesh_collision_event.cc40
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc40
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_simulation.cc39
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_time_step_event.cc37
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc57
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_simulation_time.cc31
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c2
-rw-r--r--source/blender/python/intern/bpy_driver.c2
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c2
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h22
-rw-r--r--source/blender/render/intern/source/pipeline.c2
-rw-r--r--source/blender/render/intern/source/render_texture.c77
-rw-r--r--source/blender/windowmanager/CMakeLists.txt4
-rw-r--r--source/blender/windowmanager/WM_api.h3
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c4
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c20
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c16
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c4
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c39
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c8
-rw-r--r--source/blender/windowmanager/intern/wm_window.c13
-rw-r--r--source/blender/windowmanager/wm_window.h7
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h5
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c21
-rw-r--r--source/creator/CMakeLists.txt40
-rw-r--r--source/creator/creator.c4
-rw-r--r--source/creator/creator_signals.c86
m---------source/tools0
-rw-r--r--tests/CMakeLists.txt18
-rw-r--r--tests/gtests/CMakeLists.txt1
-rw-r--r--tests/gtests/blenkernel/BKE_armature_test.cc89
-rw-r--r--tests/gtests/blenkernel/BKE_fcurve_test.cc211
-rw-r--r--tests/gtests/blenkernel/CMakeLists.txt (renamed from intern/string/CMakeLists.txt)30
-rw-r--r--tests/gtests/blenlib/BLI_array_ref_test.cc4
-rw-r--r--tests/gtests/blenlib/BLI_array_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_index_range_test.cc4
-rw-r--r--tests/gtests/blenlib/BLI_linear_allocator_test.cc113
-rw-r--r--tests/gtests/blenlib/BLI_linklist_lockfree_test.cc9
-rw-r--r--tests/gtests/blenlib/BLI_map_test.cc19
-rw-r--r--tests/gtests/blenlib/BLI_optional_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_set_test.cc25
-rw-r--r--tests/gtests/blenlib/BLI_stack_cxx_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_string_map_test.cc21
-rw-r--r--tests/gtests/blenlib/BLI_string_ref_test.cc15
-rw-r--r--tests/gtests/blenlib/BLI_task_performance_test.cc86
-rw-r--r--tests/gtests/blenlib/BLI_task_test.cc90
-rw-r--r--tests/gtests/blenlib/BLI_vector_set_test.cc25
-rw-r--r--tests/gtests/blenlib/BLI_vector_test.cc16
-rw-r--r--tests/gtests/blenlib/CMakeLists.txt1
-rw-r--r--tests/gtests/usd/hierarchy_context_order_test.cc44
-rw-r--r--tests/python/CMakeLists.txt16
-rw-r--r--[-rwxr-xr-x]tests/python/alembic_tests.py0
-rw-r--r--[-rwxr-xr-x]tests/python/cycles_render_tests.py0
-rw-r--r--[-rwxr-xr-x]tests/python/eevee_render_tests.py0
-rw-r--r--[-rwxr-xr-x]tests/python/ffmpeg_tests.py0
-rw-r--r--[-rwxr-xr-x]tests/python/opengl_draw_tests.py0
-rw-r--r--[-rwxr-xr-x]tests/python/workbench_render_tests.py0
718 files changed, 24398 insertions, 14923 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5fb0393dcda..19f25e3c108 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -138,11 +138,6 @@ get_blender_version()
#-----------------------------------------------------------------------------
# Options
-# First platform specific non-cached vars
-if(UNIX AND NOT (APPLE OR HAIKU))
- set(WITH_X11 ON)
-endif()
-
# Blender internal features
option(WITH_BLENDER "Build blender (disable to build only the blender player)" ON)
mark_as_advanced(WITH_BLENDER)
@@ -207,7 +202,15 @@ mark_as_advanced(WITH_GHOST_DEBUG)
option(WITH_GHOST_SDL "Enable building Blender against SDL for windowing rather than the native APIs" OFF)
mark_as_advanced(WITH_GHOST_SDL)
-if(WITH_X11)
+if(UNIX AND NOT (APPLE OR HAIKU))
+ option(WITH_GHOST_X11 "Enable building Blender against X11 for windowing" ON)
+ mark_as_advanced(WITH_GHOST_X11)
+
+ option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing (under development)" OFF)
+ mark_as_advanced(WITH_GHOST_WAYLAND)
+endif()
+
+if(WITH_GHOST_X11)
option(WITH_GHOST_XDND "Enable drag'n'drop support on X11 using XDND protocol" ON)
endif()
@@ -232,7 +235,7 @@ if(UNIX AND NOT APPLE)
mark_as_advanced(WITH_OPENMP_STATIC)
endif()
-if(WITH_X11)
+if(WITH_GHOST_X11)
option(WITH_X11_XINPUT "Enable X11 Xinput (tablet support and unicode input)" ON)
option(WITH_X11_XF86VMODE "Enable X11 video mode switching" ON)
option(WITH_X11_XFIXES "Enable X11 XWayland cursor warping workaround" ON)
@@ -323,6 +326,10 @@ option(WITH_FREESTYLE "Enable Freestyle (advanced edges rendering)" ON)
option(WITH_NEW_OBJECT_TYPES "Enable new hair and pointcloud objects (use for development only, don't save in files)" OFF)
mark_as_advanced(WITH_NEW_OBJECT_TYPES)
+# New simulation data block
+option(WITH_NEW_SIMULATION_TYPE "Enable simulation data block (use for development only, don't save in files)" OFF)
+mark_as_advanced(WITH_NEW_SIMULATION_TYPE)
+
# Misc
if(WIN32)
option(WITH_INPUT_IME "Enable Input Method Editor (IME) for complex Asian character input" ON)
@@ -429,6 +436,8 @@ endif()
option(WITH_GTESTS "Enable GTest unit testing" OFF)
option(WITH_OPENGL_RENDER_TESTS "Enable OpenGL render related unit testing (Experimental)" OFF)
option(WITH_OPENGL_DRAW_TESTS "Enable OpenGL UI drawing related unit testing (Experimental)" OFF)
+set(TEST_PYTHON_EXE "" CACHE PATH "Python executable to run unit tests")
+mark_as_advanced(TEST_PYTHON_EXE)
# Documentation
if(UNIX AND NOT APPLE)
@@ -469,6 +478,8 @@ endif()
if(CMAKE_COMPILER_IS_GNUCC)
option(WITH_LINKER_GOLD "Use ld.gold linker which is usually faster than ld.bfd" ON)
mark_as_advanced(WITH_LINKER_GOLD)
+ option(WITH_LINKER_LLD "Use ld.lld linker which is usually faster than ld.gold" OFF)
+ mark_as_advanced(WITH_LINKER_LLD)
endif()
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
@@ -532,6 +543,15 @@ if(WIN32)
option(WITH_WINDOWS_BUNDLE_CRT "Bundle the C runtime for install free distribution." ON)
mark_as_advanced(WITH_WINDOWS_BUNDLE_CRT)
+ option(WITH_WINDOWS_SCCACHE "Use sccache to speed up builds (Ninja builder only)" OFF)
+ mark_as_advanced(WITH_WINDOWS_SCCACHE)
+
+ option(WITH_WINDOWS_PDB "Generate a pdb file for client side stacktraces" ON)
+ mark_as_advanced(WITH_WINDOWS_PDB)
+
+ option(WITH_WINDOWS_STRIPPED_PDB "Use a stripped PDB file" On)
+ mark_as_advanced(WITH_WINDOWS_STRIPPED_PDB)
+
endif()
# The following only works with the Ninja generator in CMake >= 3.0.
@@ -678,7 +698,8 @@ if(WITH_INSTALL_PORTABLE)
endif()
if(WITH_GHOST_SDL OR WITH_HEADLESS)
- set(WITH_X11 OFF)
+ set(WITH_GHOST_WAYLAND OFF)
+ set(WITH_GHOST_X11 OFF)
set(WITH_X11_XINPUT OFF)
set(WITH_X11_XF86VMODE OFF)
set(WITH_X11_XFIXES OFF)
diff --git a/GNUmakefile b/GNUmakefile
index 98bfded4ec7..e3bb3eaff7a 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -71,17 +71,6 @@ Testing Targets
which are tagged to use the stricter formatting
* test_deprecated:
Checks for deprecation tags in our code which may need to be removed
- * test_style_c:
- Checks C/C++ conforms with blenders style guide:
- https://wiki.blender.org/wiki/Source/Code_Style
- * test_style_c_qtc:
- Same as test_style but outputs QtCreator tasks format
- * test_style_osl:
- Checks OpenShadingLanguage conforms with blenders style guide:
- https://wiki.blender.org/wiki/Source/Code_Style
- * test_style_osl_qtc:
- Checks OpenShadingLanguage conforms with blenders style guide:
- https://wiki.blender.org/wiki/Source/Code_Style
Static Source Code Checking
Not associated with building Blender.
@@ -402,45 +391,6 @@ test_cmake: .FORCE
test_deprecated: .FORCE
$(PYTHON) tests/check_deprecated.py
-test_style_c: .FORCE
- # run our own checks on C/C++ style
- PYTHONIOENCODING=utf_8 $(PYTHON) \
- "$(BLENDER_DIR)/source/tools/check_source/check_style_c.py" \
- "$(BLENDER_DIR)/source/blender" \
- "$(BLENDER_DIR)/source/creator" \
- --no-length-check
-
-test_style_c_qtc: .FORCE
- # run our own checks on C/C++ style
- USE_QTC_TASK=1 \
- PYTHONIOENCODING=utf_8 $(PYTHON) \
- "$(BLENDER_DIR)/source/tools/check_source/check_style_c.py" \
- "$(BLENDER_DIR)/source/blender" \
- "$(BLENDER_DIR)/source/creator" \
- --no-length-check \
- > \
- "$(BLENDER_DIR)/test_style.tasks"
- @echo "written: test_style.tasks"
-
-
-test_style_osl: .FORCE
- # run our own checks on C/C++ style
- PYTHONIOENCODING=utf_8 $(PYTHON) \
- "$(BLENDER_DIR)/source/tools/check_source/check_style_c.py" \
- "$(BLENDER_DIR)/intern/cycles/kernel/shaders" \
- "$(BLENDER_DIR)/release/scripts/templates_osl"
-
-
-test_style_osl_qtc: .FORCE
- # run our own checks on C/C++ style
- USE_QTC_TASK=1 \
- PYTHONIOENCODING=utf_8 $(PYTHON) \
- "$(BLENDER_DIR)/source/tools/check_source/check_style_c.py" \
- "$(BLENDER_DIR)/intern/cycles/kernel/shaders" \
- "$(BLENDER_DIR)/release/scripts/templates_osl" \
- > \
- "$(BLENDER_DIR)/test_style.tasks"
- @echo "written: test_style.tasks"
# -----------------------------------------------------------------------------
# Project Files
diff --git a/build_files/build_environment/cmake/openimagedenoise.cmake b/build_files/build_environment/cmake/openimagedenoise.cmake
index b20bb838ede..1332a38fea6 100644
--- a/build_files/build_environment/cmake/openimagedenoise.cmake
+++ b/build_files/build_environment/cmake/openimagedenoise.cmake
@@ -21,7 +21,7 @@ set(OIDN_EXTRA_ARGS
-DWITH_EXAMPLE=OFF
-DWITH_TEST=OFF
-DTBB_ROOT=${LIBDIR}/tbb
- -DTBB_STATIC_LIB=ON
+ -DTBB_STATIC_LIB=${TBB_STATIC_LIBRARY}
-DOIDN_STATIC_LIB=ON
)
diff --git a/build_files/build_environment/cmake/opensubdiv.cmake b/build_files/build_environment/cmake/opensubdiv.cmake
index 5c1ebe46a20..9ec849a219b 100644
--- a/build_files/build_environment/cmake/opensubdiv.cmake
+++ b/build_files/build_environment/cmake/opensubdiv.cmake
@@ -36,7 +36,7 @@ if(WIN32)
set(OPENSUBDIV_EXTRA_ARGS
${OPENSUBDIV_EXTRA_ARGS}
-DTBB_INCLUDE_DIR=${LIBDIR}/tbb/include
- -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/tbb_static.lib
+ -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/tbb.lib
-DCLEW_INCLUDE_DIR=${LIBDIR}/clew/include/CL
-DCLEW_LIBRARY=${LIBDIR}/clew/lib/clew${LIBEXT}
-DCUEW_INCLUDE_DIR=${LIBDIR}/cuew/include
diff --git a/build_files/build_environment/cmake/tbb.cmake b/build_files/build_environment/cmake/tbb.cmake
index 8bd2f3160d0..1cb852fb5d1 100644
--- a/build_files/build_environment/cmake/tbb.cmake
+++ b/build_files/build_environment/cmake/tbb.cmake
@@ -20,8 +20,10 @@ if(WIN32)
-DTBB_BUILD_SHARED=On
-DTBB_BUILD_TBBMALLOC=On
-DTBB_BUILD_TBBMALLOC_PROXY=On
- -DTBB_BUILD_STATIC=On
-)
+ -DTBB_BUILD_STATIC=Off
+ )
+ set(TBB_LIBRARY tbb)
+ set(TBB_STATIC_LIBRARY Off)
else()
set(TBB_EXTRA_ARGS
-DTBB_BUILD_SHARED=Off
@@ -29,6 +31,8 @@ else()
-DTBB_BUILD_TBBMALLOC_PROXY=Off
-DTBB_BUILD_STATIC=On
)
+ set(TBB_LIBRARY tbb_static)
+ set(TBB_STATIC_LIBRARY On)
endif()
# CMake script for TBB from https://github.com/wjakob/tbb/blob/master/CMakeLists.txt
@@ -46,7 +50,8 @@ ExternalProject_Add(external_tbb
if(WIN32)
if(BUILD_MODE STREQUAL Release)
ExternalProject_Add_Step(external_tbb after_install
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_static.lib ${HARVEST_TARGET}/tbb/lib/tbb.lib
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb.lib ${HARVEST_TARGET}/tbb/lib/tbb.lib
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb.dll ${HARVEST_TARGET}/tbb/lib/tbb.dll
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc.dll ${HARVEST_TARGET}/tbb/lib/tbbmalloc.dll
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_proxy.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc_proxy.lib
@@ -57,7 +62,12 @@ if(WIN32)
endif()
if(BUILD_MODE STREQUAL Debug)
ExternalProject_Add_Step(external_tbb after_install
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_static.lib ${HARVEST_TARGET}/tbb/lib/tbb_debug.lib
+ # findtbb.cmake in some deps *NEEDS* to find tbb.lib even if they are not going to use it
+ # to make that test pass, we place a copy with the right name in the lib folder.
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_debug.lib ${LIBDIR}/tbb/lib/tbb.lib
+ # Normal collection of build artifacts
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_debug.lib ${HARVEST_TARGET}/tbb/lib/debug/tbb_debug.lib
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_debug.dll ${HARVEST_TARGET}/tbb/lib/debug/tbb_debug.dll
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_proxy.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc_proxy_debug.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc.dll ${HARVEST_TARGET}/tbb/lib/debug/tbbmalloc.dll
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_proxy.dll ${HARVEST_TARGET}/tbb/lib/debug/tbbmalloc_proxy.dll
diff --git a/build_files/build_environment/cmake/usd.cmake b/build_files/build_environment/cmake/usd.cmake
index c3594390f80..505607535e9 100644
--- a/build_files/build_environment/cmake/usd.cmake
+++ b/build_files/build_environment/cmake/usd.cmake
@@ -23,8 +23,8 @@ set(USD_EXTRA_ARGS
-DBoost_USE_STATIC_RUNTIME=OFF
-DBOOST_ROOT=${LIBDIR}/boost
-DTBB_INCLUDE_DIRS=${LIBDIR}/tbb/include
- -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/${LIBPREFIX}tbb_static${LIBEXT}
- -DTbb_TBB_LIBRARY=${LIBDIR}/tbb/lib/${LIBPREFIX}tbb_static${LIBEXT}
+ -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/${LIBPREFIX}${TBB_LIBRARY}${LIBEXT}
+ -DTbb_TBB_LIBRARY=${LIBDIR}/tbb/lib/${LIBPREFIX}${TBB_LIBRARY}${LIBEXT}
# This is a preventative measure that avoids possible conflicts when add-ons
# try to load another USD library into the same process space.
diff --git a/build_files/build_environment/patches/cmakelists_tbb.txt b/build_files/build_environment/patches/cmakelists_tbb.txt
index da9fd938943..7edf3aa2785 100644
--- a/build_files/build_environment/patches/cmakelists_tbb.txt
+++ b/build_files/build_environment/patches/cmakelists_tbb.txt
@@ -109,6 +109,9 @@ if (WIN32)
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def
COMMENT "Preprocessing tbbmalloc.def"
)
+ list(APPEND tbb_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/tbb_resource.rc)
+ list(APPEND tbbmalloc_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/tbbmalloc.rc)
+ list(APPEND tbbmalloc_proxy_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/tbbmalloc.rc)
else()
add_custom_command(OUTPUT tbb.def
COMMAND ${CMAKE_CXX_COMPILER} -xc++ -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbb.def
@@ -145,8 +148,12 @@ if (TBB_BUILD_SHARED)
set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,${CMAKE_CURRENT_BINARY_DIR}/tbb.def")
elseif(WIN32)
set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "/DEF:${CMAKE_CURRENT_BINARY_DIR}/tbb.def")
+
endif()
install(TARGETS tbb DESTINATION lib)
+ if(WIN32)
+ set_target_properties(tbb PROPERTIES OUTPUT_NAME "tbb$<$<CONFIG:Debug>:_debug>")
+ endif()
endif()
if(CMAKE_COMPILER_IS_GNUCC)
@@ -196,7 +203,7 @@ if(TBB_BUILD_TBBMALLOC_PROXY)
add_library(tbbmalloc_proxy SHARED ${tbbmalloc_proxy_src})
set_property(TARGET tbbmalloc_proxy APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1")
set_property(TARGET tbbmalloc_proxy APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI})
- link_libraries(tbbmalloc_proxy tbbmalloc)
+ target_link_libraries(tbbmalloc_proxy tbbmalloc)
install(TARGETS tbbmalloc_proxy DESTINATION lib)
endif()
endif()
diff --git a/build_files/build_environment/patches/openimagedenoise.diff b/build_files/build_environment/patches/openimagedenoise.diff
index f83b0776c30..7bfc3aa2eba 100644
--- a/build_files/build_environment/patches/openimagedenoise.diff
+++ b/build_files/build_environment/patches/openimagedenoise.diff
@@ -18,17 +18,6 @@ diff --git a/mkl-dnn/cmake/TBB.cmake b/mkl-dnn/cmake/TBB.cmake
index 0711e699..c14210b6 100644
--- a/mkl-dnn/cmake/TBB.cmake
+++ b/mkl-dnn/cmake/TBB.cmake
-@@ -90,8 +90,8 @@ if(WIN32)
- NO_DEFAULT_PATH
- )
- set(TBB_LIB_DIR ${TBB_ROOT}/lib/${TBB_ARCH}/${TBB_VCVER})
-- find_library(TBB_LIBRARY tbb PATHS ${TBB_LIB_DIR} ${TBB_ROOT}/lib NO_DEFAULT_PATH)
-- find_library(TBB_LIBRARY_MALLOC tbbmalloc PATHS ${TBB_LIB_DIR} ${TBB_ROOT}/lib NO_DEFAULT_PATH)
-+ find_library(TBB_LIBRARY tbb_static PATHS ${TBB_LIB_DIR} ${TBB_ROOT}/lib NO_DEFAULT_PATH)
-+ find_library(TBB_LIBRARY_MALLOC tbbmalloc_static PATHS ${TBB_LIB_DIR} ${TBB_ROOT}/lib NO_DEFAULT_PATH)
- endif()
-
- else()
@@ -138,13 +138,13 @@ else()
set(TBB_LIBRARY_MALLOC TBB_LIBRARY_MALLOC-NOTFOUND)
if(APPLE)
diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake
index 04e1670aef6..c36b264a300 100644
--- a/build_files/cmake/Modules/GTestTesting.cmake
+++ b/build_files/cmake/Modules/GTestTesting.cmake
@@ -66,6 +66,9 @@ macro(BLENDER_SRC_GTEST_EX)
if(UNIX AND NOT APPLE)
target_link_libraries(${TARGET_NAME} bf_intern_libc_compat)
endif()
+ if(WITH_TBB)
+ target_link_libraries(${TARGET_NAME} ${TBB_LIBRARIES})
+ endif()
get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(GENERATOR_IS_MULTI_CONFIG)
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 6287da55580..d99e46ce76e 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -440,6 +440,14 @@ function(SETUP_LIBDIRS)
link_directories(${HDF5_LIBPATH})
endif()
+ if(WITH_GHOST_WAYLAND)
+ link_directories(
+ ${wayland-client_LIBRARY_DIRS}
+ ${wayland-egl_LIBRARY_DIRS}
+ ${xkbcommon_LIBRARY_DIRS}
+ ${wayland-cursor_LIBRARY_DIRS})
+ endif()
+
if(WIN32 AND NOT UNIX)
link_directories(${PTHREADS_LIBPATH})
endif()
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 050ab8f3ba1..3cfe8309bf1 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -504,7 +504,27 @@ if(WITH_SYSTEM_AUDASPACE)
endif()
endif()
-if(WITH_X11)
+if(WITH_GHOST_WAYLAND)
+ find_package(PkgConfig)
+ pkg_check_modules(wayland-client REQUIRED wayland-client>=1.12)
+ pkg_check_modules(wayland-egl REQUIRED wayland-egl)
+ pkg_check_modules(wayland-scanner REQUIRED wayland-scanner)
+ pkg_check_modules(xkbcommon REQUIRED xkbcommon)
+ pkg_check_modules(wayland-cursor REQUIRED wayland-cursor)
+
+ set(WITH_GL_EGL ON)
+
+ if(WITH_GHOST_WAYLAND)
+ list(APPEND PLATFORM_LINKLIBS
+ ${wayland-client_LIBRARIES}
+ ${wayland-egl_LIBRARIES}
+ ${xkbcommon_LIBRARIES}
+ ${wayland-cursor_LIBRARIES}
+ )
+ endif()
+endif()
+
+if(WITH_GHOST_X11)
find_package(X11 REQUIRED)
find_path(X11_XF86keysym_INCLUDE_PATH X11/XF86keysym.h ${X11_INC_SEARCH_PATH})
@@ -575,6 +595,19 @@ if(CMAKE_COMPILER_IS_GNUCC)
unset(LD_VERSION)
endif()
+ if(WITH_LINKER_LLD)
+ execute_process(
+ COMMAND ${CMAKE_C_COMPILER} -fuse-ld=lld -Wl,--version
+ ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
+ if("${LD_VERSION}" MATCHES "LLD")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=lld")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld")
+ else()
+ message(STATUS "LLD linker isn't available, using the default system linker.")
+ endif()
+ unset(LD_VERSION)
+ endif()
+
# CLang is the same as GCC for now.
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index 1ecde8635c8..5076057e0f6 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -51,6 +51,10 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
endif()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \"${CLANG_OPENMP_LIB}\"")
endif()
+ if(WITH_WINDOWS_STRIPPED_PDB)
+ message(WARNING "stripped pdb not supported with clang, disabling..")
+ set(WITH_WINDOWS_STRIPPED_PDB Off)
+ endif()
endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ${WINDOWS_USE_VISUAL_STUDIO_PROJECT_FOLDERS})
@@ -112,7 +116,7 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
list(APPEND PLATFORM_LINKLIBS
- ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32
+ ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32 version
advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp Shlwapi
)
@@ -134,7 +138,12 @@ add_definitions(-D_ALLOW_KEYWORD_MACROS)
# We want to support Windows 7 level ABI
add_definitions(-D_WIN32_WINNT=0x601)
include(build_files/cmake/platform/platform_win32_bundle_crt.cmake)
-remove_cc_flag("/MDd" "/MD")
+remove_cc_flag("/MDd" "/MD" "/Zi")
+
+if(WITH_WINDOWS_PDB)
+ set(PDB_INFO_OVERRIDE_FLAGS "/Z7")
+ set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
+endif()
if(MSVC_CLANG) # Clangs version of cl doesn't support all flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_WARN_FLAGS} /nologo /J /Gd /EHsc -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference ")
@@ -151,16 +160,30 @@ if(MSVC_VERSION GREATER 1911 AND NOT MSVC_CLANG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:twoPhase-")
endif()
+if(WITH_WINDOWS_SCCACHE AND CMAKE_VS_MSBUILD_COMMAND)
+ message(WARNING "Disabling sccache, sccache is not supported with msbuild")
+ set(WITH_WINDOWS_SCCACHE Off)
+endif()
-set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd /ZI")
-set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MDd /ZI")
-set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
-set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD")
-set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD")
-set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MD")
-set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD")
-set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MD")
-
+if(WITH_WINDOWS_SCCACHE)
+ set(CMAKE_C_COMPILER_LAUNCHER sccache)
+ set(CMAKE_CXX_COMPILER_LAUNCHER sccache)
+ set(SYMBOL_FORMAT /Z7)
+else()
+ unset(CMAKE_C_COMPILER_LAUNCHER)
+ unset(CMAKE_CXX_COMPILER_LAUNCHER)
+ set(SYMBOL_FORMAT /ZI)
+endif()
+
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd ${SYMBOL_FORMAT}")
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MDd ${SYMBOL_FORMAT}")
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD ${PDB_INFO_OVERRIDE_FLAGS}")
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD ${PDB_INFO_OVERRIDE_FLAGS}")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD ${PDB_INFO_OVERRIDE_FLAGS}")
+set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MD ${PDB_INFO_OVERRIDE_FLAGS}")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD ${SYMBOL_FORMAT}")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MD ${SYMBOL_FORMAT}")
+unset(SYMBOL_FORMAT)
# JMC is available on msvc 15.8 (1915) and up
if(MSVC_VERSION GREATER 1914 AND NOT MSVC_CLANG)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /JMC")
@@ -172,6 +195,7 @@ set(PLATFORM_LINKFLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG} /IGNORE:4099 /NODEFAUL
# Ignore meaningless for us linker warnings.
set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /ignore:4049 /ignore:4217 /ignore:4221")
+set(PLATFORM_LINKFLAGS_RELEASE "${PLATFORM_LINKFLAGS} ${PDB_INFO_OVERRIDE_LINKER_FLAGS}")
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
if(CMAKE_CL_64)
@@ -209,7 +233,7 @@ endif()
# Mark libdir as system headers with a lower warn level, to resolve some warnings
# that we have very little control over
-if(MSVC_VERSION GREATER_EQUAL 1914 AND NOT MSVC_CLANG)
+if(MSVC_VERSION GREATER_EQUAL 1914 AND NOT MSVC_CLANG AND NOT WITH_WINDOWS_SCCACHE)
add_compile_options(/experimental:external /external:templates- /external:I "${LIBDIR}" /external:W0)
endif()
@@ -572,7 +596,7 @@ if(WITH_SYSTEM_AUDASPACE)
endif()
if(WITH_TBB)
- set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
+ set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/debug/tbb_debug.lib)
set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
set(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR})
if(WITH_TBB_MALLOC_PROXY)
diff --git a/build_files/windows/configure_msbuild.cmd b/build_files/windows/configure_msbuild.cmd
index 3c1194011cd..4956f1e3ea1 100644
--- a/build_files/windows/configure_msbuild.cmd
+++ b/build_files/windows/configure_msbuild.cmd
@@ -2,6 +2,11 @@ set BUILD_GENERATOR_POST=
set BUILD_PLATFORM_SELECT=
set MSBUILD_PLATFORM=x64
+if "%BUILD_WITH_SCCACHE%"=="1" (
+ echo sccache is only supported with ninja as the build system.
+ exit /b 1
+)
+
if "%WITH_CLANG%"=="1" (
set CLANG_CMAKE_ARGS=-T"llvm"
if "%WITH_ASAN%"=="1" (
diff --git a/build_files/windows/configure_ninja.cmd b/build_files/windows/configure_ninja.cmd
index 1650e43cda9..20692847bef 100644
--- a/build_files/windows/configure_ninja.cmd
+++ b/build_files/windows/configure_ninja.cmd
@@ -6,6 +6,13 @@ if %ERRORLEVEL% NEQ 0 (
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Ninja" %TESTS_CMAKE_ARGS% -DCMAKE_BUILD_TYPE=%BUILD_TYPE%
+if "%BUILD_WITH_SCCACHE%"=="1" (
+ set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_WINDOWS_SCCACHE=On
+ if NOT "%verbose%" == "" (
+ echo Enabling sccache
+ )
+)
+
if "%WITH_CLANG%" == "1" (
set LLVM_DIR=
for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\LLVM\LLVM" /ve 2^>nul`) DO set LLVM_DIR=%%C
diff --git a/build_files/windows/parse_arguments.cmd b/build_files/windows/parse_arguments.cmd
index 4ee05bfde7d..54dc41ece87 100644
--- a/build_files/windows/parse_arguments.cmd
+++ b/build_files/windows/parse_arguments.cmd
@@ -86,6 +86,8 @@ if NOT "%1" == "" (
set BUILD_UPDATE_ARGS="--no-libraries"
) else if "%1" == "ninja" (
SET BUILD_WITH_NINJA=1
+ ) else if "%1" == "sccache" (
+ SET BUILD_WITH_SCCACHE=1
) else if "%1" == "clean" (
set MUST_CLEAN=1
) else if "%1" == "verbose" (
diff --git a/build_files/windows/reset_variables.cmd b/build_files/windows/reset_variables.cmd
index 48a61aff44a..262874713eb 100644
--- a/build_files/windows/reset_variables.cmd
+++ b/build_files/windows/reset_variables.cmd
@@ -30,3 +30,4 @@ set WITH_PYDEBUG=
set PYDEBUG_CMAKE_ARGS=
set FORMAT=
set TEST=
+set BUILD_WITH_SCCACHE=
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index ecd60957f2b..dea06a8cfdb 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = "V2.83"
+PROJECT_NUMBER = "V2.90"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index e79aba0e988..235c2fa931a 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -72,7 +72,7 @@ if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV)
endif()
endif()
-if(WITH_X11 AND WITH_GHOST_XDND)
+if(WITH_GHOST_X11 AND WITH_GHOST_XDND)
add_subdirectory(xdnd)
endif()
diff --git a/extern/audaspace/bindings/C/AUD_Device.cpp b/extern/audaspace/bindings/C/AUD_Device.cpp
index 441f228deac..d4643094bc2 100644
--- a/extern/audaspace/bindings/C/AUD_Device.cpp
+++ b/extern/audaspace/bindings/C/AUD_Device.cpp
@@ -290,14 +290,14 @@ AUD_API AUD_Device* AUD_Device_getCurrent()
return new AUD_Device(device);
}
-AUD_API void AUD_seekSynchronizer(AUD_Handle* handle, float time)
+AUD_API void AUD_seekSynchronizer(AUD_Handle* handle, double time)
{
auto synchronizer = DeviceManager::getDevice()->getSynchronizer();
if(synchronizer)
synchronizer->seek(*reinterpret_cast<std::shared_ptr<IHandle>*>(handle), time);
}
-AUD_API float AUD_getSynchronizerPosition(AUD_Handle* handle)
+AUD_API double AUD_getSynchronizerPosition(AUD_Handle* handle)
{
auto synchronizer = DeviceManager::getDevice()->getSynchronizer();
if(synchronizer)
diff --git a/extern/audaspace/bindings/C/AUD_Device.h b/extern/audaspace/bindings/C/AUD_Device.h
index 0dfa21f0660..05e004a17db 100644
--- a/extern/audaspace/bindings/C/AUD_Device.h
+++ b/extern/audaspace/bindings/C/AUD_Device.h
@@ -221,14 +221,14 @@ extern AUD_API AUD_Device* AUD_Device_getCurrent();
* \param handle Playback handle.
* \param time Time in seconds to seek to.
*/
-extern AUD_API void AUD_seekSynchronizer(AUD_Handle* handle, float time);
+extern AUD_API void AUD_seekSynchronizer(AUD_Handle* handle, double time);
/**
* Returns the current sound scene playback time.
* \param handle Playback handle.
* \return The playback time in seconds.
*/
-extern AUD_API float AUD_getSynchronizerPosition(AUD_Handle* handle);
+extern AUD_API double AUD_getSynchronizerPosition(AUD_Handle* handle);
/**
* Starts the playback of jack transport if possible.
diff --git a/extern/audaspace/bindings/C/AUD_DynamicMusic.cpp b/extern/audaspace/bindings/C/AUD_DynamicMusic.cpp
index bb7a129dde3..62e626cdc6c 100644
--- a/extern/audaspace/bindings/C/AUD_DynamicMusic.cpp
+++ b/extern/audaspace/bindings/C/AUD_DynamicMusic.cpp
@@ -101,14 +101,14 @@ AUD_API int AUD_DynamicMusic_pause(AUD_DynamicMusic* player)
return (*player)->pause();
}
-AUD_API int AUD_DynamicMusic_seek(AUD_DynamicMusic* player, float position)
+AUD_API int AUD_DynamicMusic_seek(AUD_DynamicMusic* player, double position)
{
assert(player);
return (*player)->seek(position);
}
-AUD_API float AUD_DynamicMusic_getPosition(AUD_DynamicMusic* player)
+AUD_API double AUD_DynamicMusic_getPosition(AUD_DynamicMusic* player)
{
assert(player);
@@ -141,4 +141,4 @@ AUD_API int AUD_DynamicMusic_stop(AUD_DynamicMusic* player)
assert(player);
return (*player)->stop();
-} \ No newline at end of file
+}
diff --git a/extern/audaspace/bindings/C/AUD_DynamicMusic.h b/extern/audaspace/bindings/C/AUD_DynamicMusic.h
index c362479591e..b8b78e57b55 100644
--- a/extern/audaspace/bindings/C/AUD_DynamicMusic.h
+++ b/extern/audaspace/bindings/C/AUD_DynamicMusic.h
@@ -103,14 +103,14 @@ extern AUD_API int AUD_DynamicMusic_pause(AUD_DynamicMusic* player);
* \param position The new position from which to play back, in seconds.
* \return 0 if the seeking wasn't possible.
*/
-extern AUD_API int AUD_DynamicMusic_seek(AUD_DynamicMusic* player, float position);
+extern AUD_API int AUD_DynamicMusic_seek(AUD_DynamicMusic* player, double position);
/**
* Retrieves the position of the current scene of a dynamic music player.
* \param player The DynamicMusic object.
* \return The position of the current playing scene.
*/
-extern AUD_API float AUD_DynamicMusic_getPosition(AUD_DynamicMusic* player);
+extern AUD_API double AUD_DynamicMusic_getPosition(AUD_DynamicMusic* player);
/**
* Retrieves the volume of the current scene of a dynamic music player.
@@ -142,4 +142,4 @@ extern AUD_API int AUD_DynamicMusic_stop(AUD_DynamicMusic* player);
#ifdef __cplusplus
}
-#endif \ No newline at end of file
+#endif
diff --git a/extern/audaspace/bindings/C/AUD_Handle.cpp b/extern/audaspace/bindings/C/AUD_Handle.cpp
index 265c7bf08d2..88d46d635e3 100644
--- a/extern/audaspace/bindings/C/AUD_Handle.cpp
+++ b/extern/audaspace/bindings/C/AUD_Handle.cpp
@@ -259,13 +259,13 @@ AUD_API int AUD_Handle_setPitch(AUD_Handle* handle, float value)
return (*handle)->setPitch(value);
}
-AUD_API float AUD_Handle_getPosition(AUD_Handle* handle)
+AUD_API double AUD_Handle_getPosition(AUD_Handle* handle)
{
assert(handle);
return (*handle)->getPosition();
}
-AUD_API int AUD_Handle_setPosition(AUD_Handle* handle, float value)
+AUD_API int AUD_Handle_setPosition(AUD_Handle* handle, double value)
{
assert(handle);
return (*handle)->seek(value);
diff --git a/extern/audaspace/bindings/C/AUD_Handle.h b/extern/audaspace/bindings/C/AUD_Handle.h
index 27cbd251de5..2182346c451 100644
--- a/extern/audaspace/bindings/C/AUD_Handle.h
+++ b/extern/audaspace/bindings/C/AUD_Handle.h
@@ -211,14 +211,14 @@ extern AUD_API int AUD_Handle_setPitch(AUD_Handle* handle, float value);
* param handle The handle to get the position from.
* return The position of the handle.
*/
-extern AUD_API float AUD_Handle_getPosition(AUD_Handle* handle);
+extern AUD_API double AUD_Handle_getPosition(AUD_Handle* handle);
/**
* Sets the position of a handle.
* param handle The handle to set the position from.
* param value The new position to set.
*/
-extern AUD_API int AUD_Handle_setPosition(AUD_Handle* handle, float value);
+extern AUD_API int AUD_Handle_setPosition(AUD_Handle* handle, double value);
/**
* Retrieves the relative of a handle.
diff --git a/extern/audaspace/bindings/C/AUD_Sequence.cpp b/extern/audaspace/bindings/C/AUD_Sequence.cpp
index d278cb148a1..e3f88629657 100644
--- a/extern/audaspace/bindings/C/AUD_Sequence.cpp
+++ b/extern/audaspace/bindings/C/AUD_Sequence.cpp
@@ -41,7 +41,7 @@ AUD_API void AUD_Sequence_free(AUD_Sound* sequence)
delete sequence;
}
-AUD_API AUD_SequenceEntry* AUD_Sequence_add(AUD_Sound* sequence, AUD_Sound* sound, float begin, float end, float skip)
+AUD_API AUD_SequenceEntry* AUD_Sequence_add(AUD_Sound* sequence, AUD_Sound* sound, double begin, double end, double skip)
{
if(!sound)
return new AUD_SequenceEntry(((Sequence *)sequence->get())->add(AUD_Sound(), begin, end, skip));
@@ -160,7 +160,7 @@ AUD_API void AUD_Sequence_setSpeedOfSound(AUD_Sound* sequence, float value)
-AUD_API void AUD_SequenceEntry_move(AUD_SequenceEntry* entry, float begin, float end, float skip)
+AUD_API void AUD_SequenceEntry_move(AUD_SequenceEntry* entry, double begin, double end, double skip)
{
(*entry)->move(begin, end, skip);
}
diff --git a/extern/audaspace/bindings/C/AUD_Sequence.h b/extern/audaspace/bindings/C/AUD_Sequence.h
index 668960c7d50..bdf1a61a2de 100644
--- a/extern/audaspace/bindings/C/AUD_Sequence.h
+++ b/extern/audaspace/bindings/C/AUD_Sequence.h
@@ -55,7 +55,7 @@ extern AUD_API void AUD_Sequence_free(AUD_Sound* sequence);
* \param skip How much seconds should be skipped at the beginning.
* \return The entry added.
*/
-extern AUD_API AUD_SequenceEntry* AUD_Sequence_add(AUD_Sound* sequence, AUD_Sound* sound, float begin, float end, float skip);
+extern AUD_API AUD_SequenceEntry* AUD_Sequence_add(AUD_Sound* sequence, AUD_Sound* sound, double begin, double end, double skip);
/**
* Removes an entry from the scene.
@@ -167,7 +167,7 @@ extern AUD_API void AUD_Sequence_setSpeedOfSound(AUD_Sound* sequence, float valu
* \param end The new end time or a negative value if unknown.
* \param skip How many seconds to skip at the beginning.
*/
-extern AUD_API void AUD_SequenceEntry_move(AUD_SequenceEntry* entry, float begin, float end, float skip);
+extern AUD_API void AUD_SequenceEntry_move(AUD_SequenceEntry* entry, double begin, double end, double skip);
/**
* Writes animation data to a sequenced entry.
diff --git a/extern/audaspace/bindings/C/AUD_Special.cpp b/extern/audaspace/bindings/C/AUD_Special.cpp
index 30148fa1487..c7155276a30 100644
--- a/extern/audaspace/bindings/C/AUD_Special.cpp
+++ b/extern/audaspace/bindings/C/AUD_Special.cpp
@@ -175,7 +175,7 @@ static void pauseSound(AUD_Handle* handle)
(*handle)->pause();
}
-AUD_API AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, float seconds)
+AUD_API AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, double seconds)
{
auto device = DeviceManager::getDevice();
@@ -336,7 +336,7 @@ AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start
}
}
-AUD_API AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, float start)
+AUD_API AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, double start)
{
try
{
diff --git a/extern/audaspace/bindings/C/AUD_Special.h b/extern/audaspace/bindings/C/AUD_Special.h
index ab79ae915a2..9faf9e4ee74 100644
--- a/extern/audaspace/bindings/C/AUD_Special.h
+++ b/extern/audaspace/bindings/C/AUD_Special.h
@@ -45,7 +45,7 @@ extern AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float
* \param seconds The time in seconds.
* \return The silence handle.
*/
-extern AUD_API AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, float seconds);
+extern AUD_API AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, double seconds);
/**
* Reads a sound into a buffer for drawing at a specific sampling rate.
@@ -101,7 +101,7 @@ extern AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned in
* \param start The start time of the mixdown in the sound scene.
* \return The read device for the mixdown.
*/
-extern AUD_API AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, float start);
+extern AUD_API AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, double start);
/**
* Initializes audio routines (FFMPEG/JACK if it is enabled).
diff --git a/extern/audaspace/bindings/doc/device.rst b/extern/audaspace/bindings/doc/device.rst
index fd6b334022c..d6f49bd7407 100644
--- a/extern/audaspace/bindings/doc/device.rst
+++ b/extern/audaspace/bindings/doc/device.rst
@@ -4,4 +4,5 @@ Device
.. currentmodule:: aud
.. autoclass:: Device
:members:
+ :noindex:
diff --git a/extern/audaspace/bindings/doc/handle.rst b/extern/audaspace/bindings/doc/handle.rst
index aceedbca3a6..1d118e1ef62 100644
--- a/extern/audaspace/bindings/doc/handle.rst
+++ b/extern/audaspace/bindings/doc/handle.rst
@@ -4,4 +4,5 @@ Handle
.. currentmodule:: aud
.. autoclass:: Handle
:members:
+ :noindex:
diff --git a/extern/audaspace/bindings/doc/index.rst b/extern/audaspace/bindings/doc/index.rst
index b8a26822949..cc6a543067d 100644
--- a/extern/audaspace/bindings/doc/index.rst
+++ b/extern/audaspace/bindings/doc/index.rst
@@ -7,6 +7,7 @@ Welcome to audaspace's documentation!
=====================================
.. automodule:: aud
+ :no-members:
This documentation is valid for both the Python and C bindings of audaspace. If you are looking for installation instructions check the `C++ API documentation <../index.html>`_. As C is not an object oriented language everything is accessible via functions where the first paramter is always the object. For methods these are named as ``AUD_ClassName_method()`` and properties are accessed via ``AUD_ClassName_property_get/set()``. Python users simply ``import aud`` to access the library.
@@ -18,7 +19,7 @@ This documentation is valid for both the Python and C bindings of audaspace. If
Classes:
.. toctree::
- :maxdepth: 2
+ :maxdepth: 1
device
sound
diff --git a/extern/audaspace/bindings/doc/sequence.rst b/extern/audaspace/bindings/doc/sequence.rst
index 16fcb00f4dc..51aef1a1d37 100644
--- a/extern/audaspace/bindings/doc/sequence.rst
+++ b/extern/audaspace/bindings/doc/sequence.rst
@@ -4,4 +4,5 @@ Sequence
.. currentmodule:: aud
.. autoclass:: Sequence
:members:
+ :noindex:
diff --git a/extern/audaspace/bindings/doc/sequence_entry.rst b/extern/audaspace/bindings/doc/sequence_entry.rst
index 0a3d83388e9..797b950dcdd 100644
--- a/extern/audaspace/bindings/doc/sequence_entry.rst
+++ b/extern/audaspace/bindings/doc/sequence_entry.rst
@@ -4,4 +4,5 @@ Sequence Entry
.. currentmodule:: aud
.. autoclass:: SequenceEntry
:members:
+ :noindex:
diff --git a/extern/audaspace/bindings/doc/sound.rst b/extern/audaspace/bindings/doc/sound.rst
index 2f14721cf3a..d88c113eead 100644
--- a/extern/audaspace/bindings/doc/sound.rst
+++ b/extern/audaspace/bindings/doc/sound.rst
@@ -4,4 +4,5 @@ Sound
.. currentmodule:: aud
.. autoclass:: Sound
:members:
+ :noindex:
diff --git a/extern/audaspace/bindings/doc/tutorials.rst b/extern/audaspace/bindings/doc/tutorials.rst
index 2a0e7541861..919c9083fc8 100644
--- a/extern/audaspace/bindings/doc/tutorials.rst
+++ b/extern/audaspace/bindings/doc/tutorials.rst
@@ -40,7 +40,7 @@ and create a :func:`aud.Sound.sine` signal with a frequency of 440 Hz.
sine = aud.Sound.sine(440)
.. note:: At this point nothing is playing back yet,
-:class:`aud.Sound` objects are just descriptions of sounds.
+ :class:`aud.Sound` objects are just descriptions of sounds.
However instead of a sine wave, we would like to have a square wave
to produce a more retro gaming sound. We could of course use the
diff --git a/extern/audaspace/bindings/python/PyDynamicMusic.cpp b/extern/audaspace/bindings/python/PyDynamicMusic.cpp
index cab856359e0..8a7d8265bf4 100644
--- a/extern/audaspace/bindings/python/PyDynamicMusic.cpp
+++ b/extern/audaspace/bindings/python/PyDynamicMusic.cpp
@@ -228,9 +228,9 @@ PyDoc_STRVAR(M_aud_DynamicMusic_position_doc,
static int
DynamicMusic_set_position(DynamicMusicP* self, PyObject* args, void* nothing)
{
- float position;
+ double position;
- if(!PyArg_Parse(args, "f:position", &position))
+ if(!PyArg_Parse(args, "d:position", &position))
return -1;
try
@@ -252,7 +252,7 @@ DynamicMusic_get_position(DynamicMusicP* self, void* nothing)
{
try
{
- return Py_BuildValue("f", (*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->getPosition());
+ return Py_BuildValue("d", (*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->getPosition());
}
catch(aud::Exception& e)
{
diff --git a/extern/audaspace/bindings/python/PyHandle.cpp b/extern/audaspace/bindings/python/PyHandle.cpp
index 828c1b1afef..4ecf2ffd210 100644
--- a/extern/audaspace/bindings/python/PyHandle.cpp
+++ b/extern/audaspace/bindings/python/PyHandle.cpp
@@ -696,7 +696,7 @@ Handle_get_position(Handle* self, void* nothing)
{
try
{
- return Py_BuildValue("f", (*reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle))->getPosition());
+ return Py_BuildValue("d", (*reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle))->getPosition());
}
catch(Exception& e)
{
@@ -708,9 +708,9 @@ Handle_get_position(Handle* self, void* nothing)
static int
Handle_set_position(Handle* self, PyObject* args, void* nothing)
{
- float position;
+ double position;
- if(!PyArg_Parse(args, "f:position", &position))
+ if(!PyArg_Parse(args, "d:position", &position))
return -1;
try
diff --git a/extern/audaspace/bindings/python/PySequence.cpp b/extern/audaspace/bindings/python/PySequence.cpp
index 2e08059cefb..26f0c9e566f 100644
--- a/extern/audaspace/bindings/python/PySequence.cpp
+++ b/extern/audaspace/bindings/python/PySequence.cpp
@@ -104,11 +104,11 @@ PyDoc_STRVAR(M_aud_Sequence_add_doc,
" :arg sound: The sound this entry should play.\n"
" :type sound: :class:`Sound`\n"
" :arg begin: The start time.\n"
- " :type begin: float\n"
+ " :type begin: double\n"
" :arg end: The end time or a negative value if determined by the sound.\n"
- " :type end: float\n"
+ " :type end: double\n"
" :arg skip: How much seconds should be skipped at the beginning.\n"
- " :type skip: float\n"
+ " :type skip: double\n"
" :return: The entry added.\n"
" :rtype: :class:`SequenceEntry`");
@@ -116,13 +116,13 @@ static PyObject *
Sequence_add(Sequence* self, PyObject* args, PyObject* kwds)
{
PyObject* object;
- float begin;
- float end = -1.0f;
- float skip = 0.0f;
+ double begin;
+ double end = -1.0;
+ double skip = 0.0;
static const char* kwlist[] = {"sound", "begin", "end", "skip", nullptr};
- if(!PyArg_ParseTupleAndKeywords(args, kwds, "Of|ff:add", const_cast<char**>(kwlist), &object, &begin, &end, &skip))
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "Od|dd:add", const_cast<char**>(kwlist), &object, &begin, &end, &skip))
return nullptr;
Sound* sound = checkSound(object);
diff --git a/extern/audaspace/bindings/python/PySequenceEntry.cpp b/extern/audaspace/bindings/python/PySequenceEntry.cpp
index a1bf3db21d2..74c038de0b0 100644
--- a/extern/audaspace/bindings/python/PySequenceEntry.cpp
+++ b/extern/audaspace/bindings/python/PySequenceEntry.cpp
@@ -46,18 +46,18 @@ PyDoc_STRVAR(M_aud_SequenceEntry_move_doc,
".. classmethod:: move()\n\n"
" Moves the entry.\n\n"
" :arg begin: The new start time.\n"
- " :type begin: float\n"
+ " :type begin: double\n"
" :arg end: The new end time or a negative value if unknown.\n"
- " :type end: float\n"
+ " :type end: double\n"
" :arg skip: How many seconds to skip at the beginning.\n"
- " :type skip: float\n");
+ " :type skip: double\n");
static PyObject *
SequenceEntry_move(SequenceEntry* self, PyObject* args)
{
- float begin, end, skip;
+ double begin, end, skip;
- if(!PyArg_ParseTuple(args, "fff:move", &begin, &end, &skip))
+ if(!PyArg_ParseTuple(args, "ddd:move", &begin, &end, &skip))
return nullptr;
try
diff --git a/extern/audaspace/bindings/python/PySound.cpp b/extern/audaspace/bindings/python/PySound.cpp
index c37e3f7fa52..62ee3435e82 100644
--- a/extern/audaspace/bindings/python/PySound.cpp
+++ b/extern/audaspace/bindings/python/PySound.cpp
@@ -1394,7 +1394,7 @@ PyDoc_STRVAR(M_aud_Sound_threshold_doc,
" with a amplitude >= threshold to 1, all <= -threshold to -1 and\n"
" all between to 0.\n\n"
" :arg threshold: Threshold value over which an amplitude counts\n"
- " non-zero.\n"
+ " non-zero.\n\n"
":type threshold: float\n"
":return: The created :class:`Sound` object.\n"
":rtype: :class:`Sound`");
@@ -1434,7 +1434,8 @@ PyDoc_STRVAR(M_aud_Sound_volume_doc,
" :type volume: float\n"
" :return: The created :class:`Sound` object.\n"
" :rtype: :class:`Sound`\n\n"
- " .. note:: Should be in the range [0, 1] to avoid clipping.\n\n"
+ " .. note::\n\n"
+ " Should be in the range [0, 1] to avoid clipping.\n\n"
" .. note::\n\n"
" This is a filter function, you might consider using\n"
" :attr:`Handle.volume` instead.");
@@ -1475,8 +1476,8 @@ PyDoc_STRVAR(M_aud_Sound_join_doc,
" :return: The created :class:`Sound` object.\n"
" :rtype: :class:`Sound`\n\n"
" .. note::\n\n"
- " The two factories have to have the same specifications\n"
- " (channels and samplerate).");
+ " The two factories have to have the same specifications\n"
+ " (channels and samplerate).");
static PyObject *
Sound_join(Sound* self, PyObject* object)
diff --git a/extern/audaspace/include/devices/DefaultSynchronizer.h b/extern/audaspace/include/devices/DefaultSynchronizer.h
index 31f6c65219c..e818306603c 100644
--- a/extern/audaspace/include/devices/DefaultSynchronizer.h
+++ b/extern/audaspace/include/devices/DefaultSynchronizer.h
@@ -33,8 +33,8 @@ AUD_NAMESPACE_BEGIN
class AUD_API DefaultSynchronizer : public ISynchronizer
{
public:
- virtual void seek(std::shared_ptr<IHandle> handle, float time);
- virtual float getPosition(std::shared_ptr<IHandle> handle);
+ virtual void seek(std::shared_ptr<IHandle> handle, double time);
+ virtual double getPosition(std::shared_ptr<IHandle> handle);
virtual void play();
virtual void stop();
virtual void setSyncCallback(syncFunction function, void* data);
diff --git a/extern/audaspace/include/devices/IDeviceFactory.h b/extern/audaspace/include/devices/IDeviceFactory.h
index 7023cc058c5..c0769fa8015 100644
--- a/extern/audaspace/include/devices/IDeviceFactory.h
+++ b/extern/audaspace/include/devices/IDeviceFactory.h
@@ -35,6 +35,9 @@ AUD_NAMESPACE_BEGIN
class AUD_API IDeviceFactory
{
public:
+ /**
+ * Destroys the device factory.
+ */
virtual ~IDeviceFactory() {}
/**
diff --git a/extern/audaspace/include/devices/IHandle.h b/extern/audaspace/include/devices/IHandle.h
index 3f42fc33c3a..a10ef3d71e4 100644
--- a/extern/audaspace/include/devices/IHandle.h
+++ b/extern/audaspace/include/devices/IHandle.h
@@ -105,14 +105,14 @@ public:
* - false if the handle is invalid.
* \warning Whether the seek works or not depends on the sound source.
*/
- virtual bool seek(float position)=0;
+ virtual bool seek(double position)=0;
/**
* Retrieves the current playback position of a sound.
* \return The playback position in seconds, or 0.0 if the handle is
* invalid.
*/
- virtual float getPosition()=0;
+ virtual double getPosition()=0;
/**
* Returns the status of a played back sound.
diff --git a/extern/audaspace/include/devices/ISynchronizer.h b/extern/audaspace/include/devices/ISynchronizer.h
index 6f14de59565..430230fbcb3 100644
--- a/extern/audaspace/include/devices/ISynchronizer.h
+++ b/extern/audaspace/include/devices/ISynchronizer.h
@@ -56,14 +56,14 @@ public:
* @param handle The handle that should be synchronized/seeked.
* @param time The absolute time to synchronize to.
*/
- virtual void seek(std::shared_ptr<IHandle> handle, float time) = 0;
+ virtual void seek(std::shared_ptr<IHandle> handle, double time) = 0;
/**
* Retrieves the position of the synchronizer.
* @param handle The handle which is synchronized.
* @return The position in seconds.
*/
- virtual float getPosition(std::shared_ptr<IHandle> handle) = 0;
+ virtual double getPosition(std::shared_ptr<IHandle> handle) = 0;
/**
* Starts the synchronizer playback.
diff --git a/extern/audaspace/include/devices/NULLDevice.h b/extern/audaspace/include/devices/NULLDevice.h
index 76211a799b9..9af78919f88 100644
--- a/extern/audaspace/include/devices/NULLDevice.h
+++ b/extern/audaspace/include/devices/NULLDevice.h
@@ -53,8 +53,8 @@ private:
virtual bool stop();
virtual bool getKeep();
virtual bool setKeep(bool keep);
- virtual bool seek(float position);
- virtual float getPosition();
+ virtual bool seek(double position);
+ virtual double getPosition();
virtual Status getStatus();
virtual float getVolume();
virtual bool setVolume(float volume);
diff --git a/extern/audaspace/include/devices/SoftwareDevice.h b/extern/audaspace/include/devices/SoftwareDevice.h
index 8f3846394c6..e92a35e5402 100644
--- a/extern/audaspace/include/devices/SoftwareDevice.h
+++ b/extern/audaspace/include/devices/SoftwareDevice.h
@@ -180,8 +180,8 @@ protected:
virtual bool stop();
virtual bool getKeep();
virtual bool setKeep(bool keep);
- virtual bool seek(float position);
- virtual float getPosition();
+ virtual bool seek(double position);
+ virtual double getPosition();
virtual Status getStatus();
virtual float getVolume();
virtual bool setVolume(float volume);
diff --git a/extern/audaspace/include/file/IFileInput.h b/extern/audaspace/include/file/IFileInput.h
index aec929e7639..64074910d13 100644
--- a/extern/audaspace/include/file/IFileInput.h
+++ b/extern/audaspace/include/file/IFileInput.h
@@ -40,7 +40,10 @@ class Buffer;
class AUD_API IFileInput
{
public:
- virtual ~IFileInput() {};
+ /**
+ * Destroys the file input.
+ */
+ virtual ~IFileInput() {}
/**
* Creates a reader for a file to be read.
diff --git a/extern/audaspace/include/fx/Delay.h b/extern/audaspace/include/fx/Delay.h
index d6ab93ca351..d8730802c6f 100644
--- a/extern/audaspace/include/fx/Delay.h
+++ b/extern/audaspace/include/fx/Delay.h
@@ -35,7 +35,7 @@ private:
/**
* The delay in samples.
*/
- const float m_delay;
+ const double m_delay;
// delete copy constructor and operator=
Delay(const Delay&) = delete;
@@ -47,12 +47,12 @@ public:
* \param sound The input sound.
* \param delay The desired delay in seconds.
*/
- Delay(std::shared_ptr<ISound> sound, float delay = 0);
+ Delay(std::shared_ptr<ISound> sound, double delay = 0);
/**
* Returns the delay in seconds.
*/
- float getDelay() const;
+ double getDelay() const;
virtual std::shared_ptr<IReader> createReader();
};
diff --git a/extern/audaspace/include/fx/DelayReader.h b/extern/audaspace/include/fx/DelayReader.h
index fe37e56d83e..38106082020 100644
--- a/extern/audaspace/include/fx/DelayReader.h
+++ b/extern/audaspace/include/fx/DelayReader.h
@@ -52,7 +52,7 @@ public:
* \param reader The reader to read from.
* \param delay The delay in seconds.
*/
- DelayReader(std::shared_ptr<IReader> reader, float delay);
+ DelayReader(std::shared_ptr<IReader> reader, double delay);
virtual void seek(int position);
virtual int getLength() const;
diff --git a/extern/audaspace/include/fx/DynamicMusic.h b/extern/audaspace/include/fx/DynamicMusic.h
index 5d59f77401a..c2a1c75b47e 100644
--- a/extern/audaspace/include/fx/DynamicMusic.h
+++ b/extern/audaspace/include/fx/DynamicMusic.h
@@ -55,7 +55,7 @@ private:
/**
* Length of the crossfade transition in seconds, used when no custom transition has been set.
*/
- float m_fadeTime;
+ double m_fadeTime;
/**
* Handle to the playback of the current scene.
@@ -145,13 +145,13 @@ public:
* Sets the length of the crossfade transition (default 1 second).
* \param seconds The time in seconds.
*/
- void setFadeTime(float seconds);
+ void setFadeTime(double seconds);
/**
* Gets the length of the crossfade transition (default 1 second).
* \return The length of the cressfade transition in seconds.
*/
- float getFadeTime();
+ double getFadeTime();
/**
* Resumes a paused sound.
@@ -177,14 +177,14 @@ public:
* - false if the handle is invalid.
* \warning Whether the seek works or not depends on the sound source.
*/
- bool seek(float position);
+ bool seek(double position);
/**
* Retrieves the current playback position of a sound.
* \return The playback position in seconds, or 0.0 if the handle is
* invalid.
*/
- float getPosition();
+ double getPosition();
/**
* Retrieves the volume of the scenes.
diff --git a/extern/audaspace/include/fx/Fader.h b/extern/audaspace/include/fx/Fader.h
index 63280aec292..452d525e8ca 100644
--- a/extern/audaspace/include/fx/Fader.h
+++ b/extern/audaspace/include/fx/Fader.h
@@ -43,12 +43,12 @@ private:
/**
* The fading start.
*/
- const float m_start;
+ const double m_start;
/**
* The fading length.
*/
- const float m_length;
+ const double m_length;
// delete copy constructor and operator=
Fader(const Fader&) = delete;
@@ -64,7 +64,7 @@ public:
*/
Fader(std::shared_ptr<ISound> sound,
FadeType type = FADE_IN,
- float start = 0.0f, float length = 1.0f);
+ double start = 0, double length = 1);
/**
* Returns the fading type.
@@ -74,12 +74,12 @@ public:
/**
* Returns the fading start.
*/
- float getStart() const;
+ double getStart() const;
/**
* Returns the fading length.
*/
- float getLength() const;
+ double getLength() const;
virtual std::shared_ptr<IReader> createReader();
};
diff --git a/extern/audaspace/include/fx/FaderReader.h b/extern/audaspace/include/fx/FaderReader.h
index 99ea3d28938..9e5fc6d265f 100644
--- a/extern/audaspace/include/fx/FaderReader.h
+++ b/extern/audaspace/include/fx/FaderReader.h
@@ -49,12 +49,12 @@ private:
/**
* The fading start.
*/
- const float m_start;
+ const double m_start;
/**
* The fading length.
*/
- const float m_length;
+ const double m_length;
// delete copy constructor and operator=
FaderReader(const FaderReader&) = delete;
@@ -69,7 +69,7 @@ public:
* \param length How long fading should last in seconds.
*/
FaderReader(std::shared_ptr<IReader> reader, FadeType type,
- float start,float length);
+ double start,double length);
virtual void read(int& length, bool& eos, sample_t* buffer);
};
diff --git a/extern/audaspace/include/fx/Limiter.h b/extern/audaspace/include/fx/Limiter.h
index 0b5451b4eed..b3cf598db2e 100644
--- a/extern/audaspace/include/fx/Limiter.h
+++ b/extern/audaspace/include/fx/Limiter.h
@@ -35,12 +35,12 @@ private:
/**
* The start time.
*/
- const float m_start;
+ const double m_start;
/**
* The end time.
*/
- const float m_end;
+ const double m_end;
// delete copy constructor and operator=
Limiter(const Limiter&) = delete;
@@ -55,17 +55,17 @@ public:
* play to the end.
*/
Limiter(std::shared_ptr<ISound> sound,
- float start = 0, float end = -1);
+ double start = 0, double end = -1);
/**
* Returns the start time.
*/
- float getStart() const;
+ double getStart() const;
/**
* Returns the end time.
*/
- float getEnd() const;
+ double getEnd() const;
virtual std::shared_ptr<IReader> createReader();
};
diff --git a/extern/audaspace/include/fx/LimiterReader.h b/extern/audaspace/include/fx/LimiterReader.h
index 49a07b5c29e..00ad02e343d 100644
--- a/extern/audaspace/include/fx/LimiterReader.h
+++ b/extern/audaspace/include/fx/LimiterReader.h
@@ -35,12 +35,12 @@ private:
/**
* The start sample: inclusive.
*/
- const float m_start;
+ const double m_start;
/**
* The end sample: exlusive.
*/
- const float m_end;
+ const double m_end;
// delete copy constructor and operator=
LimiterReader(const LimiterReader&) = delete;
@@ -54,7 +54,7 @@ public:
* \param end The desired end time (sample exklusive), a negative value
* signals that it should play to the end.
*/
- LimiterReader(std::shared_ptr<IReader> reader, float start = 0, float end = -1);
+ LimiterReader(std::shared_ptr<IReader> reader, double start = 0, double end = -1);
virtual void seek(int position);
virtual int getLength() const;
diff --git a/extern/audaspace/include/sequence/Sequence.h b/extern/audaspace/include/sequence/Sequence.h
index 7005171e2c8..de14fd9fa38 100644
--- a/extern/audaspace/include/sequence/Sequence.h
+++ b/extern/audaspace/include/sequence/Sequence.h
@@ -151,7 +151,7 @@ public:
* \param skip How much seconds should be skipped at the beginning.
* \return The entry added.
*/
- std::shared_ptr<SequenceEntry> add(std::shared_ptr<ISound> sound, float begin, float end, float skip);
+ std::shared_ptr<SequenceEntry> add(std::shared_ptr<ISound> sound, double begin, double end, double skip);
/**
* Removes an entry from the scene.
diff --git a/extern/audaspace/include/sequence/SequenceData.h b/extern/audaspace/include/sequence/SequenceData.h
index b3df0548a4d..c3380e66924 100644
--- a/extern/audaspace/include/sequence/SequenceData.h
+++ b/extern/audaspace/include/sequence/SequenceData.h
@@ -203,7 +203,7 @@ public:
* \param skip How much seconds should be skipped at the beginning.
* \return The entry added.
*/
- std::shared_ptr<SequenceEntry> add(std::shared_ptr<ISound> sound, float begin, float end, float skip);
+ std::shared_ptr<SequenceEntry> add(std::shared_ptr<ISound> sound, double begin, double end, double skip);
/**
* Removes an entry from the scene.
diff --git a/extern/audaspace/include/sequence/SequenceEntry.h b/extern/audaspace/include/sequence/SequenceEntry.h
index 98f15faf7ff..b8e9f116ee4 100644
--- a/extern/audaspace/include/sequence/SequenceEntry.h
+++ b/extern/audaspace/include/sequence/SequenceEntry.h
@@ -55,13 +55,13 @@ private:
std::shared_ptr<ISound> m_sound;
/// The begin time.
- float m_begin;
+ double m_begin;
/// The end time.
- float m_end;
+ double m_end;
/// How many seconds are skipped at the beginning.
- float m_skip;
+ double m_skip;
/// Whether the entry is muted.
bool m_muted;
@@ -124,7 +124,7 @@ public:
* \param skip How much seconds should be skipped at the beginning.
* \param id The ID of the entry.
*/
- SequenceEntry(std::shared_ptr<ISound> sound, float begin, float end, float skip, int id);
+ SequenceEntry(std::shared_ptr<ISound> sound, double begin, double end, double skip, int id);
virtual ~SequenceEntry();
/**
@@ -155,7 +155,7 @@ public:
* \param end The new end time or a negative value if unknown.
* \param skip How many seconds to skip at the beginning.
*/
- void move(float begin, float end, float skip);
+ void move(double begin, double end, double skip);
/**
* Retrieves the muting state of the entry.
diff --git a/extern/audaspace/plugins/jack/JackDevice.cpp b/extern/audaspace/plugins/jack/JackDevice.cpp
index 1d238f74c3a..32874fd1315 100644
--- a/extern/audaspace/plugins/jack/JackDevice.cpp
+++ b/extern/audaspace/plugins/jack/JackDevice.cpp
@@ -292,7 +292,7 @@ void JackDevice::stopPlayback()
m_nextState = JackTransportStopped;
}
-void JackDevice::seekPlayback(float time)
+void JackDevice::seekPlayback(double time)
{
if(time >= 0.0f)
AUD_jack_transport_locate(m_client, time * m_specs.rate);
@@ -304,11 +304,11 @@ void JackDevice::setSyncCallback(ISynchronizer::syncFunction sync, void* data)
m_syncFuncData = data;
}
-float JackDevice::getPlaybackPosition()
+double JackDevice::getPlaybackPosition()
{
jack_position_t position;
AUD_jack_transport_query(m_client, &position);
- return position.frame / (float) m_specs.rate;
+ return position.frame / (double) m_specs.rate;
}
bool JackDevice::doesPlayback()
diff --git a/extern/audaspace/plugins/jack/JackDevice.h b/extern/audaspace/plugins/jack/JackDevice.h
index 72143eda149..4e6b1f5d12c 100644
--- a/extern/audaspace/plugins/jack/JackDevice.h
+++ b/extern/audaspace/plugins/jack/JackDevice.h
@@ -174,7 +174,7 @@ public:
* Seeks jack transport playback.
* \param time The time to seek to.
*/
- void seekPlayback(float time);
+ void seekPlayback(double time);
/**
* Sets the sync callback for jack transport playback.
@@ -187,7 +187,7 @@ public:
* Retrieves the jack transport playback time.
* \return The current time position.
*/
- float getPlaybackPosition();
+ double getPlaybackPosition();
/**
* Returns whether jack transport plays back.
diff --git a/extern/audaspace/plugins/jack/JackSynchronizer.cpp b/extern/audaspace/plugins/jack/JackSynchronizer.cpp
index cd4c448786d..0bcafa19ca5 100644
--- a/extern/audaspace/plugins/jack/JackSynchronizer.cpp
+++ b/extern/audaspace/plugins/jack/JackSynchronizer.cpp
@@ -25,12 +25,12 @@ JackSynchronizer::JackSynchronizer(JackDevice* device) :
{
}
-void JackSynchronizer::seek(std::shared_ptr<IHandle> handle, float time)
+void JackSynchronizer::seek(std::shared_ptr<IHandle> handle, double time)
{
m_device->seekPlayback(time);
}
-float JackSynchronizer::getPosition(std::shared_ptr<IHandle> handle)
+double JackSynchronizer::getPosition(std::shared_ptr<IHandle> handle)
{
return m_device->getPlaybackPosition();
}
diff --git a/extern/audaspace/plugins/jack/JackSynchronizer.h b/extern/audaspace/plugins/jack/JackSynchronizer.h
index 5c7341a7872..8a1f930ebed 100644
--- a/extern/audaspace/plugins/jack/JackSynchronizer.h
+++ b/extern/audaspace/plugins/jack/JackSynchronizer.h
@@ -48,8 +48,8 @@ public:
*/
JackSynchronizer(JackDevice* device);
- virtual void seek(std::shared_ptr<IHandle> handle, float time);
- virtual float getPosition(std::shared_ptr<IHandle> handle);
+ virtual void seek(std::shared_ptr<IHandle> handle, double time);
+ virtual double getPosition(std::shared_ptr<IHandle> handle);
virtual void play();
virtual void stop();
virtual void setSyncCallback(syncFunction function, void* data);
diff --git a/extern/audaspace/plugins/openal/OpenALDevice.cpp b/extern/audaspace/plugins/openal/OpenALDevice.cpp
index f41e9c6bef8..536ec4ccb1b 100644
--- a/extern/audaspace/plugins/openal/OpenALDevice.cpp
+++ b/extern/audaspace/plugins/openal/OpenALDevice.cpp
@@ -269,7 +269,7 @@ bool OpenALDevice::OpenALHandle::setKeep(bool keep)
return true;
}
-bool OpenALDevice::OpenALHandle::seek(float position)
+bool OpenALDevice::OpenALHandle::seek(double position)
{
if(!m_status)
return false;
@@ -335,7 +335,7 @@ bool OpenALDevice::OpenALHandle::seek(float position)
return true;
}
-float OpenALDevice::OpenALHandle::getPosition()
+double OpenALDevice::OpenALHandle::getPosition()
{
if(!m_status)
return false;
diff --git a/extern/audaspace/plugins/openal/OpenALDevice.h b/extern/audaspace/plugins/openal/OpenALDevice.h
index c2bec443933..b6ba5456d85 100644
--- a/extern/audaspace/plugins/openal/OpenALDevice.h
+++ b/extern/audaspace/plugins/openal/OpenALDevice.h
@@ -126,8 +126,8 @@ private:
virtual bool stop();
virtual bool getKeep();
virtual bool setKeep(bool keep);
- virtual bool seek(float position);
- virtual float getPosition();
+ virtual bool seek(double position);
+ virtual double getPosition();
virtual Status getStatus();
virtual float getVolume();
virtual bool setVolume(float volume);
diff --git a/extern/audaspace/src/devices/DefaultSynchronizer.cpp b/extern/audaspace/src/devices/DefaultSynchronizer.cpp
index aa8945dadaa..3ef1f0bfc41 100644
--- a/extern/audaspace/src/devices/DefaultSynchronizer.cpp
+++ b/extern/audaspace/src/devices/DefaultSynchronizer.cpp
@@ -19,12 +19,12 @@
AUD_NAMESPACE_BEGIN
-void DefaultSynchronizer::seek(std::shared_ptr<IHandle> handle, float time)
+void DefaultSynchronizer::seek(std::shared_ptr<IHandle> handle, double time)
{
handle->seek(time);
}
-float DefaultSynchronizer::getPosition(std::shared_ptr<IHandle> handle)
+double DefaultSynchronizer::getPosition(std::shared_ptr<IHandle> handle)
{
return handle->getPosition();
}
diff --git a/extern/audaspace/src/devices/NULLDevice.cpp b/extern/audaspace/src/devices/NULLDevice.cpp
index a82537f43b2..c3290465563 100644
--- a/extern/audaspace/src/devices/NULLDevice.cpp
+++ b/extern/audaspace/src/devices/NULLDevice.cpp
@@ -52,12 +52,12 @@ bool NULLDevice::NULLHandle::setKeep(bool keep)
return false;
}
-bool NULLDevice::NULLHandle::seek(float position)
+bool NULLDevice::NULLHandle::seek(double position)
{
return false;
}
-float NULLDevice::NULLHandle::getPosition()
+double NULLDevice::NULLHandle::getPosition()
{
return std::numeric_limits<float>::quiet_NaN();
}
diff --git a/extern/audaspace/src/devices/SoftwareDevice.cpp b/extern/audaspace/src/devices/SoftwareDevice.cpp
index 8c16c75e8e3..7186f8b9442 100644
--- a/extern/audaspace/src/devices/SoftwareDevice.cpp
+++ b/extern/audaspace/src/devices/SoftwareDevice.cpp
@@ -347,7 +347,7 @@ bool SoftwareDevice::SoftwareHandle::setKeep(bool keep)
return true;
}
-bool SoftwareDevice::SoftwareHandle::seek(float position)
+bool SoftwareDevice::SoftwareHandle::seek(double position)
{
if(!m_status)
return false;
@@ -366,7 +366,7 @@ bool SoftwareDevice::SoftwareHandle::seek(float position)
return true;
}
-float SoftwareDevice::SoftwareHandle::getPosition()
+double SoftwareDevice::SoftwareHandle::getPosition()
{
if(!m_status)
return false;
@@ -376,7 +376,7 @@ float SoftwareDevice::SoftwareHandle::getPosition()
if(!m_status)
return 0.0f;
- float position = m_reader->getPosition() / (float)m_device->m_specs.rate;
+ double position = m_reader->getPosition() / (double)m_device->m_specs.rate;
return position;
}
diff --git a/extern/audaspace/src/fx/Delay.cpp b/extern/audaspace/src/fx/Delay.cpp
index e2a82299bc0..3ce16f54636 100644
--- a/extern/audaspace/src/fx/Delay.cpp
+++ b/extern/audaspace/src/fx/Delay.cpp
@@ -19,13 +19,13 @@
AUD_NAMESPACE_BEGIN
-Delay::Delay(std::shared_ptr<ISound> sound, float delay) :
+Delay::Delay(std::shared_ptr<ISound> sound, double delay) :
Effect(sound),
m_delay(delay)
{
}
-float Delay::getDelay() const
+double Delay::getDelay() const
{
return m_delay;
}
diff --git a/extern/audaspace/src/fx/DelayReader.cpp b/extern/audaspace/src/fx/DelayReader.cpp
index 530aed69cba..ec171a76f93 100644
--- a/extern/audaspace/src/fx/DelayReader.cpp
+++ b/extern/audaspace/src/fx/DelayReader.cpp
@@ -20,7 +20,7 @@
AUD_NAMESPACE_BEGIN
-DelayReader::DelayReader(std::shared_ptr<IReader> reader, float delay) :
+DelayReader::DelayReader(std::shared_ptr<IReader> reader, double delay) :
EffectReader(reader),
m_delay(int((SampleRate)delay * reader->getSpecs().rate)),
m_remdelay(int((SampleRate)delay * reader->getSpecs().rate))
diff --git a/extern/audaspace/src/fx/DynamicMusic.cpp b/extern/audaspace/src/fx/DynamicMusic.cpp
index b8f5c975b3f..ad4a76fee95 100644
--- a/extern/audaspace/src/fx/DynamicMusic.cpp
+++ b/extern/audaspace/src/fx/DynamicMusic.cpp
@@ -133,14 +133,14 @@ bool DynamicMusic::addTransition(int init, int end, std::shared_ptr<ISound> soun
return false;
}
-void DynamicMusic::setFadeTime(float seconds)
+void DynamicMusic::setFadeTime(double seconds)
{
m_device->lock();
m_fadeTime = seconds;
m_device->unlock();
}
-float DynamicMusic::getFadeTime()
+double DynamicMusic::getFadeTime()
{
return m_fadeTime;
}
@@ -169,7 +169,7 @@ bool DynamicMusic::pause()
return result || resultTrans;
}
-bool DynamicMusic::seek(float position)
+bool DynamicMusic::seek(double position)
{
bool result = false;
@@ -183,9 +183,9 @@ bool DynamicMusic::seek(float position)
return result;
}
-float DynamicMusic::getPosition()
+double DynamicMusic::getPosition()
{
- float result = 0.0f;
+ double result = 0.0f;
if(m_currentHandle != nullptr)
result = m_currentHandle->getPosition();
diff --git a/extern/audaspace/src/fx/Fader.cpp b/extern/audaspace/src/fx/Fader.cpp
index 041d8369a01..778720b6059 100644
--- a/extern/audaspace/src/fx/Fader.cpp
+++ b/extern/audaspace/src/fx/Fader.cpp
@@ -18,7 +18,7 @@
AUD_NAMESPACE_BEGIN
-Fader::Fader(std::shared_ptr<ISound> sound, FadeType type, float start, float length) :
+Fader::Fader(std::shared_ptr<ISound> sound, FadeType type, double start, double length) :
Effect(sound),
m_type(type),
m_start(start),
@@ -31,12 +31,12 @@ FadeType Fader::getType() const
return m_type;
}
-float Fader::getStart() const
+double Fader::getStart() const
{
return m_start;
}
-float Fader::getLength() const
+double Fader::getLength() const
{
return m_length;
}
diff --git a/extern/audaspace/src/fx/FaderReader.cpp b/extern/audaspace/src/fx/FaderReader.cpp
index b1e23b993f3..10783f9f00c 100644
--- a/extern/audaspace/src/fx/FaderReader.cpp
+++ b/extern/audaspace/src/fx/FaderReader.cpp
@@ -20,7 +20,7 @@
AUD_NAMESPACE_BEGIN
-FaderReader::FaderReader(std::shared_ptr<IReader> reader, FadeType type, float start,float length) :
+FaderReader::FaderReader(std::shared_ptr<IReader> reader, FadeType type, double start, double length) :
EffectReader(reader),
m_type(type),
m_start(start),
@@ -36,14 +36,14 @@ void FaderReader::read(int& length, bool& eos, sample_t* buffer)
m_reader->read(length, eos, buffer);
- if((position + length) / (float)specs.rate <= m_start)
+ if((position + length) / specs.rate <= m_start)
{
if(m_type != FADE_OUT)
{
std::memset(buffer, 0, length * samplesize);
}
}
- else if(position / (float)specs.rate >= m_start+m_length)
+ else if(position / specs.rate >= m_start+m_length)
{
if(m_type == FADE_OUT)
{
@@ -58,7 +58,7 @@ void FaderReader::read(int& length, bool& eos, sample_t* buffer)
{
if(i % specs.channels == 0)
{
- volume = (((position+i)/(float)specs.rate)-m_start) / m_length;
+ volume = float((((position + i) / specs.rate) - m_start) / m_length);
if(volume > 1.0f)
volume = 1.0f;
else if(volume < 0.0f)
diff --git a/extern/audaspace/src/fx/Limiter.cpp b/extern/audaspace/src/fx/Limiter.cpp
index 38a7288e8d7..031283bb322 100644
--- a/extern/audaspace/src/fx/Limiter.cpp
+++ b/extern/audaspace/src/fx/Limiter.cpp
@@ -20,19 +20,19 @@
AUD_NAMESPACE_BEGIN
Limiter::Limiter(std::shared_ptr<ISound> sound,
- float start, float end) :
+ double start, double end) :
Effect(sound),
m_start(start),
m_end(end)
{
}
-float Limiter::getStart() const
+double Limiter::getStart() const
{
return m_start;
}
-float Limiter::getEnd() const
+double Limiter::getEnd() const
{
return m_end;
}
diff --git a/extern/audaspace/src/fx/LimiterReader.cpp b/extern/audaspace/src/fx/LimiterReader.cpp
index 1d003c29679..28eb47aed2f 100644
--- a/extern/audaspace/src/fx/LimiterReader.cpp
+++ b/extern/audaspace/src/fx/LimiterReader.cpp
@@ -21,7 +21,7 @@
AUD_NAMESPACE_BEGIN
-LimiterReader::LimiterReader(std::shared_ptr<IReader> reader, float start, float end) :
+LimiterReader::LimiterReader(std::shared_ptr<IReader> reader, double start, double end) :
EffectReader(reader),
m_start(start),
m_end(end)
diff --git a/extern/audaspace/src/respec/ChannelMapperReader.cpp b/extern/audaspace/src/respec/ChannelMapperReader.cpp
index 6558d2444f5..f7ddf3dbc73 100644
--- a/extern/audaspace/src/respec/ChannelMapperReader.cpp
+++ b/extern/audaspace/src/respec/ChannelMapperReader.cpp
@@ -16,9 +16,9 @@
#include "respec/ChannelMapperReader.h"
+#include <algorithm>
#include <cmath>
#include <limits>
-#include <algorithm>
AUD_NAMESPACE_BEGIN
diff --git a/extern/audaspace/src/respec/Mixer.cpp b/extern/audaspace/src/respec/Mixer.cpp
index d63f0bab2bb..ad8d885df4e 100644
--- a/extern/audaspace/src/respec/Mixer.cpp
+++ b/extern/audaspace/src/respec/Mixer.cpp
@@ -66,11 +66,11 @@ void Mixer::setSpecs(Specs specs)
void Mixer::clear(int length)
{
- m_buffer.assureSize(length * m_specs.channels * AUD_SAMPLE_SIZE(m_specs));
+ m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs));
m_length = length;
- std::memset(m_buffer.getBuffer(), 0, length * m_specs.channels * AUD_SAMPLE_SIZE(m_specs));
+ std::memset(m_buffer.getBuffer(), 0, length * AUD_SAMPLE_SIZE(m_specs));
}
void Mixer::mix(sample_t* buffer, int start, int length, float volume)
diff --git a/extern/audaspace/src/sequence/Sequence.cpp b/extern/audaspace/src/sequence/Sequence.cpp
index eaec4d84ae1..ab7e6e77857 100644
--- a/extern/audaspace/src/sequence/Sequence.cpp
+++ b/extern/audaspace/src/sequence/Sequence.cpp
@@ -90,7 +90,7 @@ AnimateableProperty* Sequence::getAnimProperty(AnimateablePropertyType type)
return m_sequence->getAnimProperty(type);
}
-std::shared_ptr<SequenceEntry> Sequence::add(std::shared_ptr<ISound> sound, float begin, float end, float skip)
+std::shared_ptr<SequenceEntry> Sequence::add(std::shared_ptr<ISound> sound, double begin, double end, double skip)
{
return m_sequence->add(sound, begin, end, skip);
}
diff --git a/extern/audaspace/src/sequence/SequenceData.cpp b/extern/audaspace/src/sequence/SequenceData.cpp
index fb920acc1a8..288f0bd225d 100644
--- a/extern/audaspace/src/sequence/SequenceData.cpp
+++ b/extern/audaspace/src/sequence/SequenceData.cpp
@@ -149,7 +149,7 @@ AnimateableProperty* SequenceData::getAnimProperty(AnimateablePropertyType type)
}
}
-std::shared_ptr<SequenceEntry> SequenceData::add(std::shared_ptr<ISound> sound, float begin, float end, float skip)
+std::shared_ptr<SequenceEntry> SequenceData::add(std::shared_ptr<ISound> sound, double begin, double end, double skip)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
diff --git a/extern/audaspace/src/sequence/SequenceEntry.cpp b/extern/audaspace/src/sequence/SequenceEntry.cpp
index de538199d7d..b63bdd2ffca 100644
--- a/extern/audaspace/src/sequence/SequenceEntry.cpp
+++ b/extern/audaspace/src/sequence/SequenceEntry.cpp
@@ -22,7 +22,7 @@
AUD_NAMESPACE_BEGIN
-SequenceEntry::SequenceEntry(std::shared_ptr<ISound> sound, float begin, float end, float skip, int id) :
+SequenceEntry::SequenceEntry(std::shared_ptr<ISound> sound, double begin, double end, double skip, int id) :
m_status(0),
m_pos_status(1),
m_sound_status(0),
@@ -84,7 +84,7 @@ void SequenceEntry::setSound(std::shared_ptr<ISound> sound)
}
}
-void SequenceEntry::move(float begin, float end, float skip)
+void SequenceEntry::move(double begin, double end, double skip)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
diff --git a/extern/audaspace/src/sequence/SequenceHandle.cpp b/extern/audaspace/src/sequence/SequenceHandle.cpp
index 140b1fbd94a..0437b05c85d 100644
--- a/extern/audaspace/src/sequence/SequenceHandle.cpp
+++ b/extern/audaspace/src/sequence/SequenceHandle.cpp
@@ -57,7 +57,7 @@ void SequenceHandle::start()
m_valid = m_handle.get();
}
-bool SequenceHandle::updatePosition(float position)
+bool SequenceHandle::updatePosition(double position)
{
std::lock_guard<ILockable> lock(*m_entry);
@@ -140,7 +140,7 @@ void SequenceHandle::stop()
m_3dhandle = nullptr;
}
-void SequenceHandle::update(float position, float frame, float fps)
+void SequenceHandle::update(double position, float frame, float fps)
{
if(m_sound_status != m_entry->m_sound_status)
{
@@ -229,7 +229,7 @@ void SequenceHandle::update(float position, float frame, float fps)
m_handle->setVolume(0);
}
-bool SequenceHandle::seek(float position)
+bool SequenceHandle::seek(double position)
{
if(!m_valid)
// sound not valid, aborting
@@ -240,7 +240,7 @@ bool SequenceHandle::seek(float position)
return false;
std::lock_guard<ILockable> lock(*m_entry);
- float seekpos = position - m_entry->m_begin;
+ double seekpos = position - m_entry->m_begin;
if(seekpos < 0)
seekpos = 0;
seekpos += m_entry->m_skip;
diff --git a/extern/audaspace/src/sequence/SequenceHandle.h b/extern/audaspace/src/sequence/SequenceHandle.h
index 9a77489a8f8..14a94365878 100644
--- a/extern/audaspace/src/sequence/SequenceHandle.h
+++ b/extern/audaspace/src/sequence/SequenceHandle.h
@@ -71,7 +71,7 @@ private:
* \param position Current playback position in seconds.
* \return Whether the handle is valid.
*/
- bool updatePosition(float position);
+ bool updatePosition(double position);
public:
/**
@@ -104,14 +104,14 @@ public:
* \param frame The current frame during playback.
* \param fps The animation frames per second.
*/
- void update(float position, float frame, float fps);
+ void update(double position, float frame, float fps);
/**
* Seeks the handle to a specific time position.
* \param position The time to seek to.
* \return Whether the handle is valid.
*/
- bool seek(float position);
+ bool seek(double position);
};
AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/sequence/SequenceReader.cpp b/extern/audaspace/src/sequence/SequenceReader.cpp
index 38647aaeadf..c903e8ef42e 100644
--- a/extern/audaspace/src/sequence/SequenceReader.cpp
+++ b/extern/audaspace/src/sequence/SequenceReader.cpp
@@ -49,7 +49,7 @@ void SequenceReader::seek(int position)
for(auto& handle : m_handles)
{
- handle->seek(position / m_sequence->m_specs.rate);
+ handle->seek(position / (double)m_sequence->m_specs.rate);
}
}
@@ -150,13 +150,12 @@ void SequenceReader::read(int& length, bool& eos, sample_t* buffer)
Specs specs = m_sequence->m_specs;
int pos = 0;
- float time = float(m_position) / float(specs.rate);
+ double time = double(m_position) / double(specs.rate);
float volume, frame;
int len, cfra;
Vector3 v, v2;
Quaternion q;
-
while(pos < length)
{
frame = time * m_sequence->m_fps;
@@ -187,7 +186,7 @@ void SequenceReader::read(int& length, bool& eos, sample_t* buffer)
m_device.read(reinterpret_cast<data_t*>(buffer + specs.channels * pos), len);
pos += len;
- time += float(len) / float(specs.rate);
+ time += double(len) / double(specs.rate);
}
m_position += length;
diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h
index 791dd001bbe..e5cd4a3d6ce 100644
--- a/extern/mantaflow/preprocessed/gitinfo.h
+++ b/extern/mantaflow/preprocessed/gitinfo.h
@@ -1,3 +1,3 @@
-#define MANTA_GIT_VERSION "commit 21303fab2eda588ec22988bf9e5762d2001c131f"
+#define MANTA_GIT_VERSION "commit b4a2742bd743e2913fba94dd35846042e2650212"
diff --git a/extern/mantaflow/preprocessed/plugin/extforces.cpp b/extern/mantaflow/preprocessed/plugin/extforces.cpp
index 36221fbbc10..798bb3daeee 100644
--- a/extern/mantaflow/preprocessed/plugin/extforces.cpp
+++ b/extern/mantaflow/preprocessed/plugin/extforces.cpp
@@ -244,13 +244,15 @@ struct KnApplyForce : public KernelBase {
bool additive;
};
-//! add gravity forces to all fluid cells, automatically adapts to different grid sizes
+//! add gravity forces to all fluid cells, optionally adapts to different grid sizes automatically
void addGravity(const FlagGrid &flags,
MACGrid &vel,
Vec3 gravity,
- const Grid<Real> *exclude = NULL)
+ const Grid<Real> *exclude = NULL,
+ bool scale = true)
{
- Vec3 f = gravity * flags.getParent()->getDt() / flags.getDx();
+ float gridScale = (scale) ? flags.getDx() : 1;
+ Vec3 f = gravity * flags.getParent()->getDt() / gridScale;
KnApplyForce(flags, vel, f, exclude, true);
}
static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
@@ -267,8 +269,9 @@ static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
Vec3 gravity = _args.get<Vec3>("gravity", 2, &_lock);
const Grid<Real> *exclude = _args.getPtrOpt<Grid<Real>>("exclude", 3, NULL, &_lock);
+ bool scale = _args.getOpt<bool>("scale", 4, true, &_lock);
_retval = getPyNone();
- addGravity(flags, vel, gravity, exclude);
+ addGravity(flags, vel, gravity, exclude, scale);
_args.check();
}
pbFinalizePlugin(parent, "addGravity", !noTiming);
@@ -287,14 +290,13 @@ void PbRegister_addGravity()
}
}
-//! add gravity forces to all fluid cells , but dont account for changing cell size
+//! Deprecated: use addGravity(scale=false) instead
void addGravityNoScale(const FlagGrid &flags,
MACGrid &vel,
const Vec3 &gravity,
const Grid<Real> *exclude = NULL)
{
- const Vec3 f = gravity * flags.getParent()->getDt();
- KnApplyForce(flags, vel, f, exclude, true);
+ addGravity(flags, vel, gravity, exclude, false);
}
static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
@@ -412,14 +414,17 @@ struct KnAddBuoyancy : public KernelBase {
Vec3 strength;
};
-//! add Buoyancy force based on fctor (e.g. smoke density)
+//! add Buoyancy force based on factor (e.g. smoke density), optionally adapts to different grid
+//! sizes automatically
void addBuoyancy(const FlagGrid &flags,
const Grid<Real> &density,
MACGrid &vel,
Vec3 gravity,
- Real coefficient = 1.)
+ Real coefficient = 1.,
+ bool scale = true)
{
- Vec3 f = -gravity * flags.getParent()->getDt() / flags.getParent()->getDx() * coefficient;
+ float gridScale = (scale) ? flags.getDx() : 1;
+ Vec3 f = -gravity * flags.getParent()->getDt() / gridScale * coefficient;
KnAddBuoyancy(flags, density, vel, f);
}
static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
@@ -437,8 +442,9 @@ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 2, &_lock);
Vec3 gravity = _args.get<Vec3>("gravity", 3, &_lock);
Real coefficient = _args.getOpt<Real>("coefficient", 4, 1., &_lock);
+ bool scale = _args.getOpt<bool>("scale", 5, true, &_lock);
_retval = getPyNone();
- addBuoyancy(flags, density, vel, gravity, coefficient);
+ addBuoyancy(flags, density, vel, gravity, coefficient, scale);
_args.check();
}
pbFinalizePlugin(parent, "addBuoyancy", !noTiming);
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index 4e780dc9f0f..fa18f4d793a 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -20,7 +20,6 @@
# add_subdirectory(atomic) # header only
add_subdirectory(clog)
-add_subdirectory(string)
add_subdirectory(ghost)
add_subdirectory(guardedalloc)
add_subdirectory(libmv)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 7cf615620a3..08641c05941 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -500,8 +500,9 @@ class CYCLES_RENDER_PT_light_paths_caustics(CyclesButtonsPanel, Panel):
col = layout.column()
col.prop(cscene, "blur_glossy")
- col.prop(cscene, "caustics_reflective")
- col.prop(cscene, "caustics_refractive")
+ col = layout.column(heading="Caustics", align=True)
+ col.prop(cscene, "caustics_reflective", text="Reflective")
+ col.prop(cscene, "caustics_refractive", text="Refractive")
class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel):
@@ -762,22 +763,16 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
rd = scene.render
view_layer = context.view_layer
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
+ col = layout.column(heading="Include")
col.prop(view_layer, "use_sky", text="Environment")
- col = flow.column()
col.prop(view_layer, "use_ao", text="Ambient Occlusion")
- col = flow.column()
col.prop(view_layer, "use_solid", text="Surfaces")
- col = flow.column()
col.prop(view_layer, "use_strand", text="Hair")
- col = flow.column()
col.prop(view_layer, "use_volumes", text="Volumes")
if with_freestyle:
- col = flow.column()
- col.prop(view_layer, "use_freestyle", text="Freestyle")
- col.active = rd.use_freestyle
+ sub = col.row(align=True)
+ sub.prop(view_layer, "use_freestyle", text="Freestyle")
+ sub.active = rd.use_freestyle
class CYCLES_RENDER_PT_override(CyclesButtonsPanel, Panel):
@@ -819,36 +814,27 @@ class CYCLES_RENDER_PT_passes_data(CyclesButtonsPanel, Panel):
view_layer = context.view_layer
cycles_view_layer = view_layer.cycles
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- col = flow.column()
+ col = layout.column(heading="Include", align=True)
col.prop(view_layer, "use_pass_combined")
- col = flow.column()
col.prop(view_layer, "use_pass_z")
- col = flow.column()
col.prop(view_layer, "use_pass_mist")
- col = flow.column()
col.prop(view_layer, "use_pass_normal")
- col = flow.column()
- col.prop(view_layer, "use_pass_vector")
- col.active = not rd.use_motion_blur
- col = flow.column()
+ sub = col.column()
+ sub.active = not rd.use_motion_blur
+ sub.prop(view_layer, "use_pass_vector")
col.prop(view_layer, "use_pass_uv")
- col = flow.column()
+
+ col.prop(cycles_view_layer, "denoising_store_passes", text="Denoising Data")
+
+ col = layout.column(heading="Indexes", align=True)
col.prop(view_layer, "use_pass_object_index")
- col = flow.column()
col.prop(view_layer, "use_pass_material_index")
- layout.separator()
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- col = flow.column()
- col.prop(cycles_view_layer, "denoising_store_passes", text="Denoising Data")
- col = flow.column()
+ col = layout.column(heading="Debug", align=True)
col.prop(cycles_view_layer, "pass_debug_render_time", text="Render Time")
- col = flow.column()
col.prop(cycles_view_layer, "pass_debug_sample_count", text="Sample Count")
- layout.separator()
+
layout.prop(view_layer, "pass_alpha_threshold")
@@ -866,38 +852,26 @@ class CYCLES_RENDER_PT_passes_light(CyclesButtonsPanel, Panel):
view_layer = context.view_layer
cycles_view_layer = view_layer.cycles
- split = layout.split(factor=0.35)
- split.use_property_split = False
- split.label(text="Diffuse")
- row = split.row(align=True)
- row.prop(view_layer, "use_pass_diffuse_direct", text="Direct", toggle=True)
- row.prop(view_layer, "use_pass_diffuse_indirect", text="Indirect", toggle=True)
- row.prop(view_layer, "use_pass_diffuse_color", text="Color", toggle=True)
-
- split = layout.split(factor=0.35)
- split.use_property_split = False
- split.label(text="Glossy")
- row = split.row(align=True)
- row.prop(view_layer, "use_pass_glossy_direct", text="Direct", toggle=True)
- row.prop(view_layer, "use_pass_glossy_indirect", text="Indirect", toggle=True)
- row.prop(view_layer, "use_pass_glossy_color", text="Color", toggle=True)
-
- split = layout.split(factor=0.35)
- split.use_property_split = False
- split.label(text="Transmission")
- row = split.row(align=True)
- row.prop(view_layer, "use_pass_transmission_direct", text="Direct", toggle=True)
- row.prop(view_layer, "use_pass_transmission_indirect", text="Indirect", toggle=True)
- row.prop(view_layer, "use_pass_transmission_color", text="Color", toggle=True)
-
- split = layout.split(factor=0.35)
- split.use_property_split = False
- split.label(text="Volume")
- row = split.row(align=True)
- row.prop(cycles_view_layer, "use_pass_volume_direct", text="Direct", toggle=True)
- row.prop(cycles_view_layer, "use_pass_volume_indirect", text="Indirect", toggle=True)
+ col = layout.column(heading="Diffuse", align=True)
+ col.prop(view_layer, "use_pass_diffuse_direct", text="Direct")
+ col.prop(view_layer, "use_pass_diffuse_indirect", text="Indirect")
+ col.prop(view_layer, "use_pass_diffuse_color", text="Color")
- col = layout.column(align=True)
+ col = layout.column(heading="Glossy", align=True)
+ col.prop(view_layer, "use_pass_glossy_direct", text="Direct")
+ col.prop(view_layer, "use_pass_glossy_indirect", text="Indirect")
+ col.prop(view_layer, "use_pass_glossy_color", text="Color")
+
+ col = layout.column(heading="Transmission", align=True)
+ col.prop(view_layer, "use_pass_transmission_direct", text="Direct")
+ col.prop(view_layer, "use_pass_transmission_indirect", text="Indirect")
+ col.prop(view_layer, "use_pass_transmission_color", text="Color")
+
+ col = layout.column(heading="Volume", align=True)
+ col.prop(cycles_view_layer, "use_pass_volume_direct", text="Direct")
+ col.prop(cycles_view_layer, "use_pass_volume_indirect", text="Indirect")
+
+ col = layout.column(heading="Other", align=True)
col.prop(view_layer, "use_pass_emit", text="Emission")
col.prop(view_layer, "use_pass_environment")
col.prop(view_layer, "use_pass_shadow")
@@ -918,11 +892,10 @@ class CYCLES_RENDER_PT_passes_crypto(CyclesButtonsPanel, Panel):
cycles_view_layer = context.view_layer.cycles
- row = layout.row(align=True)
- row.use_property_split = False
- row.prop(cycles_view_layer, "use_pass_crypto_object", text="Object", toggle=True)
- row.prop(cycles_view_layer, "use_pass_crypto_material", text="Material", toggle=True)
- row.prop(cycles_view_layer, "use_pass_crypto_asset", text="Asset", toggle=True)
+ col = layout.column(heading="Include", align=True)
+ col.prop(cycles_view_layer, "use_pass_crypto_object", text="Object")
+ col.prop(cycles_view_layer, "use_pass_crypto_material", text="Material")
+ col.prop(cycles_view_layer, "use_pass_crypto_asset", text="Asset")
layout.prop(cycles_view_layer, "pass_crypto_depth", text="Levels")
@@ -1012,10 +985,9 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
view_layer = context.view_layer
cycles_view_layer = view_layer.cycles
- split = layout.split()
- split.active = cycles_view_layer.use_denoising
+ layout.active = cycles_view_layer.use_denoising
- col = split.column(align=True)
+ col = layout.column()
if show_optix_denoising(context):
col.prop(cycles_view_layer, "use_optix_denoising")
@@ -1026,51 +998,29 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
return
col.prop(cycles_view_layer, "denoising_radius", text="Radius")
+
+ col = layout.column()
col.prop(cycles_view_layer, "denoising_strength", slider=True, text="Strength")
col.prop(cycles_view_layer, "denoising_feature_strength", slider=True, text="Feature Strength")
col.prop(cycles_view_layer, "denoising_relative_pca")
layout.separator()
- split = layout.split(factor=0.5)
- split.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes
-
- col = split.column()
- col.alignment = 'RIGHT'
- col.label(text="Diffuse")
+ col = layout.column()
+ col.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes
- row = split.row(align=True)
- row.use_property_split = False
+ row = col.row(heading="Diffuse", align=True)
row.prop(cycles_view_layer, "denoising_diffuse_direct", text="Direct", toggle=True)
row.prop(cycles_view_layer, "denoising_diffuse_indirect", text="Indirect", toggle=True)
- split = layout.split(factor=0.5)
- split.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes
-
- col = split.column()
- col.alignment = 'RIGHT'
- col.label(text="Glossy")
-
- row = split.row(align=True)
- row.use_property_split = False
+ row = col.row(heading="Glossy", align=True)
row.prop(cycles_view_layer, "denoising_glossy_direct", text="Direct", toggle=True)
row.prop(cycles_view_layer, "denoising_glossy_indirect", text="Indirect", toggle=True)
- split = layout.split(factor=0.5)
- split.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes
-
- col = split.column()
- col.alignment = 'RIGHT'
- col.label(text="Transmission")
-
- row = split.row(align=True)
- row.use_property_split = False
+ row = col.row(heading="Transmission", align=True)
row.prop(cycles_view_layer, "denoising_transmission_direct", text="Direct", toggle=True)
row.prop(cycles_view_layer, "denoising_transmission_indirect", text="Indirect", toggle=True)
- split = layout.split(factor=0.5)
- split.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes
-
class CYCLES_PT_post_processing(CyclesButtonsPanel, Panel):
bl_label = "Post Processing"
@@ -1084,7 +1034,7 @@ class CYCLES_PT_post_processing(CyclesButtonsPanel, Panel):
rd = context.scene.render
- col = layout.column(align=True)
+ col = layout.column(align=True, heading="Pipeline")
col.prop(rd, "use_compositing")
col.prop(rd, "use_sequencer")
@@ -1273,22 +1223,18 @@ class CYCLES_OBJECT_PT_visibility(CyclesButtonsPanel, Panel):
layout = self.layout
layout.use_property_split = True
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
- layout = self.layout
ob = context.object
- col = flow.column()
- col.prop(ob, "hide_viewport", text="Show in Viewports", invert_checkbox=True, toggle=False)
- col = flow.column()
- col.prop(ob, "hide_render", text="Show in Renders", invert_checkbox=True, toggle=False)
- col = flow.column()
- col.prop(ob, "hide_select", text="Selectable", invert_checkbox=True, toggle=False)
+ layout.prop(ob, "hide_select", text="Selectable", invert_checkbox=True, toggle=False)
+
+ col = layout.column(heading="Show in")
+ col.prop(ob, "hide_viewport", text="Viewports", invert_checkbox=True, toggle=False)
+ col.prop(ob, "hide_render", text="Renders", invert_checkbox=True, toggle=False)
if has_geometry_visibility(ob):
cob = ob.cycles
- col = flow.column()
+ col = layout.column(heading="Mask")
col.prop(cob, "is_shadow_catcher")
- col = flow.column()
col.prop(cob, "is_holdout")
@@ -1312,24 +1258,16 @@ class CYCLES_OBJECT_PT_visibility_ray_visibility(CyclesButtonsPanel, Panel):
cob = ob.cycles
visibility = ob.cycles_visibility
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
+ col = layout.column()
col.prop(visibility, "camera")
- col = flow.column()
col.prop(visibility, "diffuse")
- col = flow.column()
col.prop(visibility, "glossy")
- col = flow.column()
col.prop(visibility, "transmission")
- col = flow.column()
col.prop(visibility, "scatter")
if ob.type != 'LIGHT':
- col = flow.column()
- col.prop(visibility, "shadow")
-
- layout.separator()
+ sub = col.column()
+ sub.prop(visibility, "shadow")
class CYCLES_OBJECT_PT_visibility_culling(CyclesButtonsPanel, Panel):
@@ -1352,15 +1290,13 @@ class CYCLES_OBJECT_PT_visibility_culling(CyclesButtonsPanel, Panel):
ob = context.object
cob = ob.cycles
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
- col.active = scene.render.use_simplify and cscene.use_camera_cull
- col.prop(cob, "use_camera_cull")
+ row = layout.row()
+ row.active = scene.render.use_simplify and cscene.use_camera_cull
+ row.prop(cob, "use_camera_cull")
- col = flow.column()
- col.active = scene.render.use_simplify and cscene.use_distance_cull
- col.prop(cob, "use_distance_cull")
+ row = layout.row()
+ row.active = scene.render.use_simplify and cscene.use_distance_cull
+ row.prop(cob, "use_distance_cull")
def panel_node_draw(layout, id_data, output_type, input_name):
@@ -1474,6 +1410,8 @@ class CYCLES_LIGHT_PT_nodes(CyclesButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
light = context.light
panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface')
@@ -1523,6 +1461,8 @@ class CYCLES_WORLD_PT_surface(CyclesButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
world = context.world
if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
@@ -1542,6 +1482,8 @@ class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
world = context.world
panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
@@ -1729,6 +1671,8 @@ class CYCLES_MATERIAL_PT_surface(CyclesButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
mat = context.material
if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'):
layout.prop(mat, "diffuse_color")
@@ -1747,6 +1691,8 @@ class CYCLES_MATERIAL_PT_volume(CyclesButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
mat = context.material
# cmat = mat.cycles
@@ -1765,6 +1711,8 @@ class CYCLES_MATERIAL_PT_displacement(CyclesButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
mat = context.material
panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
@@ -1906,26 +1854,24 @@ class CYCLES_RENDER_PT_bake_influence(CyclesButtonsPanel, Panel):
sub.prop(cbk, "normal_b", text="B")
elif cscene.bake_type == 'COMBINED':
- row = col.row(align=True)
- row.use_property_split = False
- row.prop(cbk, "use_pass_direct", toggle=True)
- row.prop(cbk, "use_pass_indirect", toggle=True)
- flow = col.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=True)
+ col = layout.column(heading="Lighting", align=True)
+ col.prop(cbk, "use_pass_direct")
+ col.prop(cbk, "use_pass_indirect")
- flow.active = cbk.use_pass_direct or cbk.use_pass_indirect
- flow.prop(cbk, "use_pass_diffuse")
- flow.prop(cbk, "use_pass_glossy")
- flow.prop(cbk, "use_pass_transmission")
- flow.prop(cbk, "use_pass_ambient_occlusion")
- flow.prop(cbk, "use_pass_emit")
+ col = layout.column(heading="Contributions", align=True)
+ col.active = cbk.use_pass_direct or cbk.use_pass_indirect
+ col.prop(cbk, "use_pass_diffuse")
+ col.prop(cbk, "use_pass_glossy")
+ col.prop(cbk, "use_pass_transmission")
+ col.prop(cbk, "use_pass_ambient_occlusion")
+ col.prop(cbk, "use_pass_emit")
elif cscene.bake_type in {'DIFFUSE', 'GLOSSY', 'TRANSMISSION'}:
- row = col.row(align=True)
- row.use_property_split = False
- row.prop(cbk, "use_pass_direct", toggle=True)
- row.prop(cbk, "use_pass_indirect", toggle=True)
- row.prop(cbk, "use_pass_color", toggle=True)
+ col = layout.column(heading="Contributions", align=True)
+ col.prop(cbk, "use_pass_direct")
+ col.prop(cbk, "use_pass_indirect")
+ col.prop(cbk, "use_pass_color")
class CYCLES_RENDER_PT_bake_selected_to_active(CyclesButtonsPanel, Panel):
@@ -2131,17 +2077,17 @@ class CYCLES_RENDER_PT_simplify_culling(CyclesButtonsPanel, Panel):
layout.active = rd.use_simplify
- col = layout.column()
- col.prop(cscene, "use_camera_cull")
- sub = col.column()
+ row = layout.row(heading="Camera Culling")
+ row.prop(cscene, "use_camera_cull", text="")
+ sub = row.column()
sub.active = cscene.use_camera_cull
- sub.prop(cscene, "camera_cull_margin")
+ sub.prop(cscene, "camera_cull_margin", text="")
- col = layout.column()
- col.prop(cscene, "use_distance_cull")
- sub = col.column()
+ row = layout.row(heading="Distance Culling")
+ row.prop(cscene, "use_distance_cull", text="")
+ sub = row.column()
sub.active = cscene.use_distance_cull
- sub.prop(cscene, "distance_cull_margin", text="Distance")
+ sub.prop(cscene, "distance_cull_margin", text="")
class CYCLES_VIEW3D_PT_shading_render_pass(Panel):
diff --git a/intern/dualcon/dualcon.h b/intern/dualcon/dualcon.h
index e9bff72a1ce..60cec101545 100644
--- a/intern/dualcon/dualcon.h
+++ b/intern/dualcon/dualcon.h
@@ -29,7 +29,7 @@ typedef float (*DualConCo)[3];
typedef unsigned int (*DualConTri)[3];
-typedef unsigned int(*DualConLoop);
+typedef unsigned int *DualConLoop;
typedef struct DualConInput {
DualConLoop mloop;
diff --git a/intern/dualcon/intern/octree.cpp b/intern/dualcon/intern/octree.cpp
index 70b3b8bb457..c9d5639cb5d 100644
--- a/intern/dualcon/intern/octree.cpp
+++ b/intern/dualcon/intern/octree.cpp
@@ -480,7 +480,7 @@ void Octree::trace()
if (chdpath != NULL) {
dc_printf("there are incomplete rings.\n");
printPaths(chdpath);
- };
+ }
}
Node *Octree::trace(Node *newnode, int *st, int len, int depth, PathList *&paths)
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 68fc9637e02..699ac4afe88 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -21,7 +21,6 @@
set(INC
.
../glew-mx
- ../string
../../source/blender/imbuf
../../source/blender/makesdna
)
@@ -86,7 +85,6 @@ set(SRC
set(LIB
bf_intern_glew_mx
- bf_intern_string
${GLEW_LIBRARY}
)
@@ -151,7 +149,7 @@ if(WITH_HEADLESS OR WITH_GHOST_SDL)
endif()
endif()
-elseif(APPLE AND NOT WITH_X11)
+elseif(APPLE AND NOT WITH_GHOST_X11)
list(APPEND SRC
intern/GHOST_DisplayManagerCocoa.mm
intern/GHOST_SystemCocoa.mm
@@ -179,73 +177,143 @@ elseif(APPLE AND NOT WITH_X11)
)
endif()
-elseif(WITH_X11)
- list(APPEND INC_SYS
- ${X11_X11_INCLUDE_PATH}
- )
-
- list(APPEND SRC
- intern/GHOST_DisplayManagerX11.cpp
- intern/GHOST_SystemX11.cpp
- intern/GHOST_TaskbarX11.cpp
- intern/GHOST_WindowX11.cpp
-
- intern/GHOST_DisplayManagerX11.h
- intern/GHOST_IconX11.h
- intern/GHOST_SystemX11.h
- intern/GHOST_TaskbarX11.h
- intern/GHOST_WindowX11.h
- )
+elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
+ if(WITH_GHOST_X11)
+ list(APPEND INC_SYS
+ ${X11_X11_INCLUDE_PATH}
+ )
- if(NOT WITH_GL_EGL)
list(APPEND SRC
- intern/GHOST_ContextGLX.cpp
-
- intern/GHOST_ContextGLX.h
+ intern/GHOST_DisplayManagerX11.cpp
+ intern/GHOST_SystemX11.cpp
+ intern/GHOST_TaskbarX11.cpp
+ intern/GHOST_WindowX11.cpp
+
+ intern/GHOST_DisplayManagerX11.h
+ intern/GHOST_IconX11.h
+ intern/GHOST_SystemX11.h
+ intern/GHOST_TaskbarX11.h
+ intern/GHOST_WindowX11.h
)
- endif()
- if(WITH_GHOST_XDND)
- add_definitions(-DWITH_XDND)
+ if(NOT WITH_GL_EGL)
+ list(APPEND SRC
+ intern/GHOST_ContextGLX.cpp
- list(APPEND LIB
- extern_xdnd
- )
+ intern/GHOST_ContextGLX.h
+ )
+ endif()
- list(APPEND INC
- ../../extern/xdnd
- )
+ if(WITH_GHOST_XDND)
+ add_definitions(-DWITH_XDND)
- list(APPEND SRC
- intern/GHOST_DropTargetX11.cpp
+ list(APPEND LIB
+ extern_xdnd
+ )
- intern/GHOST_DropTargetX11.h
- )
+ list(APPEND INC
+ ../../extern/xdnd
+ )
+
+ list(APPEND SRC
+ intern/GHOST_DropTargetX11.cpp
+
+ intern/GHOST_DropTargetX11.h
+ )
+ endif()
+
+ if(X11_XF86keysym_INCLUDE_PATH)
+ add_definitions(-DWITH_XF86KEYSYM)
+ list(APPEND INC_SYS
+ ${X11_XF86keysym_INCLUDE_PATH}
+ )
+ endif()
+
+ if(WITH_X11_XF86VMODE)
+ add_definitions(-DWITH_X11_XF86VMODE)
+ list(APPEND INC_SYS
+ ${X11_xf86vmode_INCLUDE_PATH}
+ )
+ endif()
+
+ if(WITH_X11_XFIXES)
+ add_definitions(-DWITH_X11_XFIXES)
+ list(APPEND INC_SYS
+ ${X11_Xfixes_INCLUDE_PATH}
+ )
+ endif()
+
+ if(WITH_X11_ALPHA)
+ add_definitions(-DWITH_X11_ALPHA)
+ endif()
+
+ if(WITH_X11_XINPUT)
+ add_definitions(-DWITH_X11_XINPUT)
+ list(APPEND INC_SYS
+ ${X11_Xinput_INCLUDE_PATH}
+ )
+ endif()
+
+ add_definitions(-DWITH_GHOST_X11)
endif()
- if(X11_XF86keysym_INCLUDE_PATH)
- add_definitions(-DWITH_XF86KEYSYM)
+ if(WITH_GHOST_WAYLAND)
list(APPEND INC_SYS
- ${X11_XF86keysym_INCLUDE_PATH}
+ ${wayland-client_INCLUDE_DIRS}
+ ${wayland-egl_INCLUDE_DIRS}
+ ${xkbcommon_INCLUDE_DIRS}
+ ${wayland-cursor_INCLUDE_DIRS}
)
- endif()
- if(WITH_X11_XF86VMODE)
- add_definitions(-DWITH_X11_XF86VMODE)
- list(APPEND INC_SYS
- ${X11_xf86vmode_INCLUDE_PATH}
+ list(APPEND SRC
+ intern/GHOST_SystemWayland.cpp
+ intern/GHOST_WindowWayland.cpp
+
+ intern/GHOST_SystemWayland.h
+ intern/GHOST_WindowWayland.h
)
- endif()
- if(WITH_X11_XFIXES)
- add_definitions(-DWITH_X11_XFIXES)
+ pkg_get_variable(WAYLAND_SCANNER wayland-scanner wayland_scanner)
+ pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
+
+ # Generate protocols bindings.
+ macro(generate_protocol_bindings NAME PROT_DEF)
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.h
+ COMMAND ${WAYLAND_SCANNER} client-header ${PROT_DEF} ${NAME}-client-protocol.h
+ )
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.c
+ COMMAND ${WAYLAND_SCANNER} private-code ${PROT_DEF} ${NAME}-client-protocol.c
+ DEPENDS ${NAME}-client-protocol.h
+ )
+ list(APPEND SRC
+ ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.c
+ ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.h
+ )
+ endmacro()
+
list(APPEND INC_SYS
- ${X11_Xfixes_INCLUDE_PATH}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+ # xdg-shell.
+ generate_protocol_bindings(
+ xdg-shell
+ "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml"
+ )
+ # Pointer-constraints.
+ generate_protocol_bindings(
+ pointer-constraints
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
+ )
+ # Relative-pointer.
+ generate_protocol_bindings(
+ relative-pointer
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
)
- endif()
- if(WITH_X11_ALPHA)
- add_definitions(-DWITH_X11_ALPHA)
+ add_definitions(-DWITH_GHOST_WAYLAND)
endif()
if(WITH_INPUT_NDOF)
@@ -260,14 +328,6 @@ elseif(WITH_X11)
add_definitions(-DPREFIX="${CMAKE_INSTALL_PREFIX}")
endif()
- if(WITH_X11_XINPUT)
- add_definitions(-DWITH_X11_XINPUT)
- list(APPEND INC_SYS
- ${X11_Xinput_INCLUDE_PATH}
- )
- endif()
-
- add_definitions(-DWITH_X11)
elseif(WIN32)
# # Warnings as errors, this is too strict!
diff --git a/intern/ghost/GHOST_IContext.h b/intern/ghost/GHOST_IContext.h
index 1225262a908..8c24261644a 100644
--- a/intern/ghost/GHOST_IContext.h
+++ b/intern/ghost/GHOST_IContext.h
@@ -26,7 +26,6 @@
#define __GHOST_IContext_H__
#include "GHOST_Types.h"
-#include "STR_String.h"
/**
* Interface for GHOST context.
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 58d1a08da74..9b619f5c684 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -27,6 +27,8 @@
#ifndef __GHOST_ISYSTEM_H__
#define __GHOST_ISYSTEM_H__
+#include <stdlib.h>
+
#include "GHOST_IContext.h"
#include "GHOST_ITimerTask.h"
#include "GHOST_IWindow.h"
@@ -240,7 +242,7 @@ class GHOST_ISystem {
* \param parentWindow: Parent (embedder) window
* \return The new window (or 0 if creation failed).
*/
- virtual GHOST_IWindow *createWindow(const STR_String &title,
+ virtual GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index daf07b81e01..62290d20f1c 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -27,7 +27,9 @@
#include "GHOST_Rect.h"
#include "GHOST_Types.h"
-#include "STR_String.h"
+
+#include <stdlib.h>
+#include <string>
/**
* Interface for GHOST windows.
@@ -81,13 +83,13 @@ class GHOST_IWindow {
* Sets the title displayed in the title bar.
* \param title The title to display in the title bar.
*/
- virtual void setTitle(const STR_String &title) = 0;
+ virtual void setTitle(const char *title) = 0;
/**
* Returns the title displayed in the title bar.
* \param title The title displayed in the title bar.
*/
- virtual void getTitle(STR_String &title) const = 0;
+ virtual std::string getTitle() const = 0;
/**
* Returns the window rectangle dimensions.
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index db9fd2e3bf9..843684b6d2e 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -24,6 +24,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include "GHOST_C-api.h"
#include "GHOST_IEvent.h"
@@ -527,17 +528,15 @@ void GHOST_SetTitle(GHOST_WindowHandle windowhandle, const char *title)
char *GHOST_GetTitle(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- STR_String title;
+ std::string title = window->getTitle();
- window->getTitle(title);
-
- char *ctitle = (char *)malloc(title.Length() + 1);
+ char *ctitle = (char *)malloc(title.size() + 1);
if (ctitle == NULL) {
return NULL;
}
- strcpy(ctitle, title.Ptr());
+ strcpy(ctitle, title.c_str());
return ctitle;
}
@@ -678,7 +677,7 @@ GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
return context->activateDrawingContext();
}
else {
- GHOST_PRINT("GHOST_ActivateOpenGLContext: Context not valid");
+ GHOST_PRINTF("%s: Context not valid\n", __func__);
return GHOST_kFailure;
}
}
diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h
index 0163197e14a..5b5c2688297 100644
--- a/intern/ghost/intern/GHOST_Debug.h
+++ b/intern/ghost/intern/GHOST_Debug.h
@@ -33,15 +33,11 @@
#endif
#ifdef WITH_GHOST_DEBUG
-# define GHOST_DEBUG // spit ghost events to stdout
-#endif // WITH_GHOST_DEBUG
-
-#ifdef GHOST_DEBUG
# include <iostream>
# include <stdio.h> //for printf()
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
# define GHOST_PRINT(x) \
{ \
std::cout << x; \
@@ -52,10 +48,10 @@
printf(x, __VA_ARGS__); \
} \
(void)0
-#else // GHOST_DEBUG
+#else // WITH_GHOST_DEBUG
# define GHOST_PRINT(x)
# define GHOST_PRINTF(x, ...)
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
#ifdef WITH_ASSERT_ABORT
# include <stdio.h> //for fprintf()
@@ -70,7 +66,7 @@
} \
} \
(void)0
-#elif defined(GHOST_DEBUG)
+#elif defined(WITH_GHOST_DEBUG)
# define GHOST_ASSERT(x, info) \
{ \
if (!(x)) { \
@@ -80,8 +76,8 @@
} \
} \
(void)0
-#else // GHOST_DEBUG
+#else // WITH_GHOST_DEBUG
# define GHOST_ASSERT(x, info) ((void)0)
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
#endif // __GHOST_DEBUG_H__
diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
index aabaffc7732..3557c4cd0c5 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
@@ -80,13 +80,13 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display,
GHOST_TSuccess success;
DEVMODE dm;
if (::EnumDisplaySettings(display_device.DeviceName, index, &dm)) {
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n",
dm.dmPelsWidth,
dm.dmPelsHeight,
dm.dmBitsPerPel,
dm.dmDisplayFrequency);
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
setting.xPixels = dm.dmPelsWidth;
setting.yPixels = dm.dmPelsHeight;
setting.bpp = dm.dmBitsPerPel;
@@ -142,16 +142,16 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting(
* dm.dmSize = sizeof(DEVMODE);
* dm.dmDriverExtra = 0;
*/
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
printf("display change: Requested settings:\n");
printf(" dmBitsPerPel=%d\n", dm.dmBitsPerPel);
printf(" dmPelsWidth=%d\n", dm.dmPelsWidth);
printf(" dmPelsHeight=%d\n", dm.dmPelsHeight);
printf(" dmDisplayFrequency=%d\n", dm.dmDisplayFrequency);
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
LONG status = ::ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
switch (status) {
case DISP_CHANGE_SUCCESSFUL:
printf("display change: The settings change was successful.\n");
@@ -182,6 +182,6 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting(
printf("display change: Return value invalid\n");
break;
}
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
return status == DISP_CHANGE_SUCCESSFUL ? GHOST_kSuccess : GHOST_kFailure;
}
diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
index 9f8ce3b5095..fe11d9a28f2 100644
--- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
@@ -28,10 +28,10 @@
#include "utf_winfunc.h"
#include "utfconv.h"
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
// utility
void printLastError(void);
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
GHOST_DropTargetWin32::GHOST_DropTargetWin32(GHOST_WindowWin32 *window, GHOST_SystemWin32 *system)
: m_window(window), m_system(system)
@@ -209,9 +209,9 @@ void *GHOST_DropTargetWin32::getGhostData(IDataObject *pDataObject)
// return getDropDataAsBitmap(pDataObject);
break;
default:
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
::printf("\nGHOST_kDragnDropTypeUnknown");
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
return NULL;
break;
}
@@ -284,10 +284,10 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject)
// Free memory
::GlobalUnlock(stgmed.hGlobal);
::ReleaseStgMedium(&stgmed);
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
::printf("\n<converted droped unicode string>\n%s\n</droped converted unicode string>\n",
tmp_string);
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
return tmp_string;
}
}
@@ -336,9 +336,9 @@ int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out)
NULL);
if (!size) {
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
::printLastError();
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
return 0;
}
@@ -351,16 +351,16 @@ int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out)
size = ::WideCharToMultiByte(CP_ACP, 0x00000400, in, -1, (LPSTR)out, size, NULL, NULL);
if (!size) {
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
::printLastError();
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
::free(out);
out = NULL;
}
return size;
}
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
void printLastError(void)
{
LPTSTR s;
@@ -378,4 +378,4 @@ void printLastError(void)
LocalFree(s);
}
}
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
diff --git a/intern/ghost/intern/GHOST_EventKey.h b/intern/ghost/intern/GHOST_EventKey.h
index 24e20b20659..8f59c555914 100644
--- a/intern/ghost/intern/GHOST_EventKey.h
+++ b/intern/ghost/intern/GHOST_EventKey.h
@@ -25,6 +25,8 @@
#ifndef __GHOST_EVENTKEY_H__
#define __GHOST_EVENTKEY_H__
+#include <string.h>
+
#include "GHOST_Event.h"
/**
diff --git a/intern/ghost/intern/GHOST_EventPrinter.h b/intern/ghost/intern/GHOST_EventPrinter.h
index fad9ec3cc69..ead16525ec6 100644
--- a/intern/ghost/intern/GHOST_EventPrinter.h
+++ b/intern/ghost/intern/GHOST_EventPrinter.h
@@ -27,8 +27,6 @@
#include "GHOST_IEventConsumer.h"
-#include "STR_String.h"
-
/**
* An Event consumer that prints all the events to standard out.
* Really useful when debugging.
diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp
index 914f6712676..7c12bfe0306 100644
--- a/intern/ghost/intern/GHOST_ISystem.cpp
+++ b/intern/ghost/intern/GHOST_ISystem.cpp
@@ -27,20 +27,22 @@
#include "GHOST_ISystem.h"
-#ifdef WITH_X11
+#if defined(WITH_HEADLESS)
+# include "GHOST_SystemNULL.h"
+#elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND)
+# include "GHOST_SystemWayland.h"
# include "GHOST_SystemX11.h"
-#else
-# ifdef WITH_HEADLESS
-# include "GHOST_SystemNULL.h"
-# elif defined(WITH_GHOST_SDL)
-# include "GHOST_SystemSDL.h"
-# elif defined(WIN32)
-# include "GHOST_SystemWin32.h"
-# else
-# ifdef __APPLE__
-# include "GHOST_SystemCocoa.h"
-# endif
-# endif
+# include <stdexcept>
+#elif defined(WITH_GHOST_X11)
+# include "GHOST_SystemX11.h"
+#elif defined(WITH_GHOST_WAYLAND)
+# include "GHOST_SystemWayland.h"
+#elif defined(WITH_GHOST_SDL)
+# include "GHOST_SystemSDL.h"
+#elif defined(WIN32)
+# include "GHOST_SystemWin32.h"
+#elif defined(__APPLE__)
+# include "GHOST_SystemCocoa.h"
#endif
GHOST_ISystem *GHOST_ISystem::m_system = NULL;
@@ -49,20 +51,29 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
{
GHOST_TSuccess success;
if (!m_system) {
-#ifdef WITH_X11
- m_system = new GHOST_SystemX11();
-#else
-# ifdef WITH_HEADLESS
+#if defined(WITH_HEADLESS)
m_system = new GHOST_SystemNULL();
-# elif defined(WITH_GHOST_SDL)
+#elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND)
+ /* Special case, try Wayland, fall back to X11. */
+ try {
+ m_system = new GHOST_SystemWayland();
+ }
+ catch (const std::runtime_error &) {
+ /* fallback to X11. */
+ }
+ if (!m_system) {
+ m_system = new GHOST_SystemX11();
+ }
+#elif defined(WITH_GHOST_X11)
+ m_system = new GHOST_SystemX11();
+#elif defined(WITH_GHOST_WAYLAND)
+ m_system = new GHOST_SystemWayland();
+#elif defined(WITH_GHOST_SDL)
m_system = new GHOST_SystemSDL();
-# elif defined(WIN32)
+#elif defined(WIN32)
m_system = new GHOST_SystemWin32();
-# else
-# ifdef __APPLE__
+#elif defined(__APPLE__)
m_system = new GHOST_SystemCocoa();
-# endif
-# endif
#endif
success = m_system != NULL ? GHOST_kSuccess : GHOST_kFailure;
}
diff --git a/intern/ghost/intern/GHOST_IXrGraphicsBinding.h b/intern/ghost/intern/GHOST_IXrGraphicsBinding.h
index cddb557d163..5794a682023 100644
--- a/intern/ghost/intern/GHOST_IXrGraphicsBinding.h
+++ b/intern/ghost/intern/GHOST_IXrGraphicsBinding.h
@@ -33,7 +33,7 @@ class GHOST_IXrGraphicsBinding {
public:
union {
-#if defined(WITH_X11)
+#if defined(WITH_GHOST_X11)
XrGraphicsBindingOpenGLXlibKHR glx;
#elif defined(WIN32)
XrGraphicsBindingOpenGLWin32KHR wgl;
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index a9fbadab37a..dda78c0ac5b 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -19,6 +19,8 @@
#include "GHOST_EventKey.h"
#include "GHOST_EventNDOF.h"
#include "GHOST_WindowManager.h"
+
+#include <limits.h>
#include <math.h>
#include <stdio.h> // for error/info reporting
#include <string.h> // for memory functions
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 85eb6d58679..587e4c28102 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -309,12 +309,12 @@ GHOST_TSuccess GHOST_System::init()
m_windowManager = new GHOST_WindowManager();
m_eventManager = new GHOST_EventManager();
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
if (m_eventManager) {
m_eventPrinter = new GHOST_EventPrinter();
m_eventManager->addConsumer(m_eventPrinter);
}
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
if (m_timerManager && m_windowManager && m_eventManager) {
return GHOST_kSuccess;
@@ -367,7 +367,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
GHOST_ASSERT(m_displayManager,
"GHOST_System::createFullScreenWindow(): invalid display manager");
// GHOST_PRINT("GHOST_System::createFullScreenWindow(): creating full-screen window\n");
- *window = (GHOST_Window *)createWindow(STR_String(""),
+ *window = (GHOST_Window *)createWindow("",
0,
0,
settings.xPixels,
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index eaaa2ff6ee6..0f58be49dff 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -31,9 +31,9 @@
#include "GHOST_Debug.h"
#include "GHOST_EventManager.h"
#include "GHOST_ModifierKeys.h"
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
# include "GHOST_EventPrinter.h"
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
class GHOST_DisplayManager;
class GHOST_Event;
@@ -390,9 +390,9 @@ class GHOST_System : public GHOST_ISystem {
#endif
/** Prints all the events. */
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
GHOST_EventPrinter *m_eventPrinter;
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
/** Settings of the display before the display went fullscreen. */
GHOST_DisplaySetting m_preFullScreenSetting;
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index 1e44c3e31d4..d058697470a 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -100,7 +100,7 @@ class GHOST_SystemCocoa : public GHOST_System {
* \param parentWindow Parent (embedder) window
* \return The new window (or 0 if creation failed).
*/
- GHOST_IWindow *createWindow(const STR_String &title,
+ GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 3d6d187587c..2b6a2902757 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -698,7 +698,7 @@ void GHOST_SystemCocoa::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns3
getMainDisplayDimensions(width, height);
}
-GHOST_IWindow *GHOST_SystemCocoa::createWindow(const STR_String &title,
+GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/intern/GHOST_SystemNULL.h b/intern/ghost/intern/GHOST_SystemNULL.h
index 68a726f2be8..186cb92d1aa 100644
--- a/intern/ghost/intern/GHOST_SystemNULL.h
+++ b/intern/ghost/intern/GHOST_SystemNULL.h
@@ -106,7 +106,7 @@ class GHOST_SystemNULL : public GHOST_System {
return GHOST_kFailure;
}
- GHOST_IWindow *createWindow(const STR_String &title,
+ GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index 97a75d7a0f5..b32ec4306e8 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -49,7 +49,7 @@ GHOST_SystemSDL::~GHOST_SystemSDL()
SDL_Quit();
}
-GHOST_IWindow *GHOST_SystemSDL::createWindow(const STR_String &title,
+GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h
index 1994781530b..8feec9de61d 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.h
+++ b/intern/ghost/intern/GHOST_SystemSDL.h
@@ -80,7 +80,7 @@ class GHOST_SystemSDL : public GHOST_System {
private:
GHOST_TSuccess init();
- GHOST_IWindow *createWindow(const STR_String &title,
+ GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
new file mode 100644
index 00000000000..666515ed088
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -0,0 +1,1654 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ */
+
+#include "GHOST_SystemWayland.h"
+#include "GHOST_Event.h"
+#include "GHOST_EventButton.h"
+#include "GHOST_EventCursor.h"
+#include "GHOST_EventDragnDrop.h"
+#include "GHOST_EventKey.h"
+#include "GHOST_EventWheel.h"
+#include "GHOST_WindowManager.h"
+
+#include "GHOST_ContextEGL.h"
+
+#include <EGL/egl.h>
+#include <wayland-egl.h>
+
+#include <algorithm>
+#include <atomic>
+#include <exception>
+#include <thread>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <pointer-constraints-client-protocol.h>
+#include <relative-pointer-client-protocol.h>
+#include <wayland-cursor.h>
+#include <xkbcommon/xkbcommon.h>
+
+#include <fcntl.h>
+#include <linux/input-event-codes.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <cstring>
+
+struct output_t {
+ struct wl_output *output;
+ int32_t width, height;
+ int transform;
+ int scale;
+ std::string make;
+ std::string model;
+};
+
+struct buffer_t {
+ void *data;
+ size_t size;
+};
+
+struct cursor_t {
+ bool visible;
+ struct wl_surface *surface = nullptr;
+ struct wl_buffer *buffer;
+ struct wl_cursor_image image;
+ struct buffer_t *file_buffer = nullptr;
+};
+
+struct data_offer_t {
+ std::unordered_set<std::string> types;
+ uint32_t source_actions;
+ uint32_t dnd_action;
+ struct wl_data_offer *id;
+ std::atomic<bool> in_use;
+ struct {
+ int x, y;
+ } dnd;
+};
+
+struct data_source_t {
+ struct wl_data_source *data_source;
+ /** Last device that was active. */
+ uint32_t source_serial;
+ char *buffer_out;
+};
+
+struct input_t {
+ GHOST_SystemWayland *system;
+
+ std::string name;
+ struct wl_seat *seat;
+ struct wl_pointer *pointer = nullptr;
+ struct wl_keyboard *keyboard = nullptr;
+
+ uint32_t pointer_serial;
+ int x, y;
+ GHOST_Buttons buttons;
+ struct cursor_t cursor;
+
+ struct zwp_relative_pointer_v1 *relative_pointer;
+ struct zwp_locked_pointer_v1 *locked_pointer;
+
+ struct xkb_context *xkb_context;
+ struct xkb_state *xkb_state;
+
+ struct wl_data_device *data_device = nullptr;
+ struct data_offer_t *data_offer_dnd; /* Drag & Drop. */
+ struct data_offer_t *data_offer_copy_paste; /* Copy & Paste. */
+
+ struct data_source_t *data_source;
+};
+
+struct display_t {
+ GHOST_SystemWayland *system;
+
+ struct wl_display *display;
+ struct wl_registry *registry;
+ struct wl_compositor *compositor = nullptr;
+ struct xdg_wm_base *xdg_shell = nullptr;
+ struct wl_shm *shm = nullptr;
+ std::vector<output_t *> outputs;
+ std::vector<input_t *> inputs;
+ struct wl_cursor_theme *cursor_theme = nullptr;
+ struct wl_data_device_manager *data_device_manager = nullptr;
+ struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr;
+ struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr;
+
+ std::vector<struct wl_surface *> os_surfaces;
+ std::vector<struct wl_egl_window *> os_egl_windows;
+};
+
+static void display_destroy(display_t *d)
+{
+ if (d->data_device_manager) {
+ wl_data_device_manager_destroy(d->data_device_manager);
+ }
+
+ for (output_t *output : d->outputs) {
+ wl_output_destroy(output->output);
+ delete output;
+ }
+
+ for (input_t *input : d->inputs) {
+ if (input->data_source) {
+ free(input->data_source->buffer_out);
+ if (input->data_source->data_source) {
+ wl_data_source_destroy(input->data_source->data_source);
+ }
+ delete input->data_source;
+ }
+ if (input->data_offer_copy_paste) {
+ wl_data_offer_destroy(input->data_offer_copy_paste->id);
+ delete input->data_offer_copy_paste;
+ }
+ if (input->data_device) {
+ wl_data_device_release(input->data_device);
+ }
+ if (input->pointer) {
+ if (input->cursor.file_buffer) {
+ munmap(input->cursor.file_buffer->data, input->cursor.file_buffer->size);
+ delete input->cursor.file_buffer;
+ }
+ if (input->cursor.surface) {
+ wl_surface_destroy(input->cursor.surface);
+ }
+ if (input->pointer) {
+ wl_pointer_destroy(input->pointer);
+ }
+ }
+ if (input->keyboard) {
+ wl_keyboard_destroy(input->keyboard);
+ }
+ if (input->xkb_state) {
+ xkb_state_unref(input->xkb_state);
+ }
+ if (input->xkb_context) {
+ xkb_context_unref(input->xkb_context);
+ }
+ wl_seat_destroy(input->seat);
+ delete input;
+ }
+
+ if (d->cursor_theme) {
+ wl_cursor_theme_destroy(d->cursor_theme);
+ }
+
+ if (d->shm) {
+ wl_shm_destroy(d->shm);
+ }
+
+ if (d->relative_pointer_manager) {
+ zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
+ }
+
+ if (d->pointer_constraints) {
+ zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
+ }
+
+ for (wl_egl_window *os_egl_window : d->os_egl_windows) {
+ wl_egl_window_destroy(os_egl_window);
+ }
+
+ for (wl_surface *os_surface : d->os_surfaces) {
+ wl_surface_destroy(os_surface);
+ }
+
+ if (d->compositor) {
+ wl_compositor_destroy(d->compositor);
+ }
+
+ if (d->xdg_shell) {
+ xdg_wm_base_destroy(d->xdg_shell);
+ }
+
+ if (eglGetDisplay) {
+ ::eglTerminate(eglGetDisplay(EGLNativeDisplayType(d->display)));
+ }
+
+ if (d->display) {
+ wl_display_disconnect(d->display);
+ }
+
+ delete d;
+}
+
+static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym)
+{
+
+ GHOST_TKey gkey;
+ if (sym >= XKB_KEY_0 && sym <= XKB_KEY_9) {
+ gkey = GHOST_TKey(sym);
+ }
+ else if (sym >= XKB_KEY_KP_0 && sym <= XKB_KEY_KP_9) {
+ gkey = GHOST_TKey(GHOST_kKeyNumpad0 + sym - XKB_KEY_KP_0);
+ }
+ else if (sym >= XKB_KEY_A && sym <= XKB_KEY_Z) {
+ gkey = GHOST_TKey(sym);
+ }
+ else if (sym >= XKB_KEY_a && sym <= XKB_KEY_z) {
+ gkey = GHOST_TKey(sym - XKB_KEY_a + XKB_KEY_A);
+ }
+ else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F24) {
+ gkey = GHOST_TKey(GHOST_kKeyF1 + sym - XKB_KEY_F1);
+ }
+ else {
+
+#define GXMAP(k, x, y) \
+ case x: \
+ k = y; \
+ break
+
+ switch (sym) {
+ GXMAP(gkey, XKB_KEY_BackSpace, GHOST_kKeyBackSpace);
+ GXMAP(gkey, XKB_KEY_Tab, GHOST_kKeyTab);
+ GXMAP(gkey, XKB_KEY_Linefeed, GHOST_kKeyLinefeed);
+ GXMAP(gkey, XKB_KEY_Clear, GHOST_kKeyClear);
+ GXMAP(gkey, XKB_KEY_Return, GHOST_kKeyEnter);
+
+ GXMAP(gkey, XKB_KEY_Escape, GHOST_kKeyEsc);
+ GXMAP(gkey, XKB_KEY_space, GHOST_kKeySpace);
+ GXMAP(gkey, XKB_KEY_comma, GHOST_kKeyComma);
+ GXMAP(gkey, XKB_KEY_minus, GHOST_kKeyMinus);
+ GXMAP(gkey, XKB_KEY_plus, GHOST_kKeyPlus);
+ GXMAP(gkey, XKB_KEY_period, GHOST_kKeyPeriod);
+ GXMAP(gkey, XKB_KEY_slash, GHOST_kKeySlash);
+
+ GXMAP(gkey, XKB_KEY_semicolon, GHOST_kKeySemicolon);
+ GXMAP(gkey, XKB_KEY_equal, GHOST_kKeyEqual);
+
+ GXMAP(gkey, XKB_KEY_bracketleft, GHOST_kKeyLeftBracket);
+ GXMAP(gkey, XKB_KEY_bracketright, GHOST_kKeyRightBracket);
+ GXMAP(gkey, XKB_KEY_backslash, GHOST_kKeyBackslash);
+ GXMAP(gkey, XKB_KEY_grave, GHOST_kKeyAccentGrave);
+
+ GXMAP(gkey, XKB_KEY_Shift_L, GHOST_kKeyLeftShift);
+ GXMAP(gkey, XKB_KEY_Shift_R, GHOST_kKeyRightShift);
+ GXMAP(gkey, XKB_KEY_Control_L, GHOST_kKeyLeftControl);
+ GXMAP(gkey, XKB_KEY_Control_R, GHOST_kKeyRightControl);
+ GXMAP(gkey, XKB_KEY_Alt_L, GHOST_kKeyLeftAlt);
+ GXMAP(gkey, XKB_KEY_Alt_R, GHOST_kKeyRightAlt);
+ GXMAP(gkey, XKB_KEY_Super_L, GHOST_kKeyOS);
+ GXMAP(gkey, XKB_KEY_Super_R, GHOST_kKeyOS);
+ GXMAP(gkey, XKB_KEY_Menu, GHOST_kKeyApp);
+
+ GXMAP(gkey, XKB_KEY_Caps_Lock, GHOST_kKeyCapsLock);
+ GXMAP(gkey, XKB_KEY_Num_Lock, GHOST_kKeyNumLock);
+ GXMAP(gkey, XKB_KEY_Scroll_Lock, GHOST_kKeyScrollLock);
+
+ GXMAP(gkey, XKB_KEY_Left, GHOST_kKeyLeftArrow);
+ GXMAP(gkey, XKB_KEY_KP_Left, GHOST_kKeyLeftArrow);
+ GXMAP(gkey, XKB_KEY_Right, GHOST_kKeyRightArrow);
+ GXMAP(gkey, XKB_KEY_KP_Right, GHOST_kKeyRightArrow);
+ GXMAP(gkey, XKB_KEY_Up, GHOST_kKeyUpArrow);
+ GXMAP(gkey, XKB_KEY_KP_Up, GHOST_kKeyUpArrow);
+ GXMAP(gkey, XKB_KEY_Down, GHOST_kKeyDownArrow);
+ GXMAP(gkey, XKB_KEY_KP_Down, GHOST_kKeyDownArrow);
+
+ GXMAP(gkey, XKB_KEY_Print, GHOST_kKeyPrintScreen);
+ GXMAP(gkey, XKB_KEY_Pause, GHOST_kKeyPause);
+
+ GXMAP(gkey, XKB_KEY_Insert, GHOST_kKeyInsert);
+ GXMAP(gkey, XKB_KEY_KP_Insert, GHOST_kKeyInsert);
+ GXMAP(gkey, XKB_KEY_Delete, GHOST_kKeyDelete);
+ GXMAP(gkey, XKB_KEY_KP_Delete, GHOST_kKeyDelete);
+ GXMAP(gkey, XKB_KEY_Home, GHOST_kKeyHome);
+ GXMAP(gkey, XKB_KEY_KP_Home, GHOST_kKeyHome);
+ GXMAP(gkey, XKB_KEY_End, GHOST_kKeyEnd);
+ GXMAP(gkey, XKB_KEY_KP_End, GHOST_kKeyEnd);
+ GXMAP(gkey, XKB_KEY_Page_Up, GHOST_kKeyUpPage);
+ GXMAP(gkey, XKB_KEY_KP_Page_Up, GHOST_kKeyUpPage);
+ GXMAP(gkey, XKB_KEY_Page_Down, GHOST_kKeyDownPage);
+ GXMAP(gkey, XKB_KEY_KP_Page_Down, GHOST_kKeyDownPage);
+
+ GXMAP(gkey, XKB_KEY_KP_Decimal, GHOST_kKeyNumpadPeriod);
+ GXMAP(gkey, XKB_KEY_KP_Enter, GHOST_kKeyNumpadEnter);
+ GXMAP(gkey, XKB_KEY_KP_Add, GHOST_kKeyNumpadPlus);
+ GXMAP(gkey, XKB_KEY_KP_Subtract, GHOST_kKeyNumpadMinus);
+ GXMAP(gkey, XKB_KEY_KP_Multiply, GHOST_kKeyNumpadAsterisk);
+ GXMAP(gkey, XKB_KEY_KP_Divide, GHOST_kKeyNumpadSlash);
+
+ GXMAP(gkey, XKB_KEY_XF86AudioPlay, GHOST_kKeyMediaPlay);
+ GXMAP(gkey, XKB_KEY_XF86AudioStop, GHOST_kKeyMediaStop);
+ GXMAP(gkey, XKB_KEY_XF86AudioPrev, GHOST_kKeyMediaFirst);
+ GXMAP(gkey, XKB_KEY_XF86AudioNext, GHOST_kKeyMediaLast);
+ default:
+ GHOST_PRINT("unhandled key: " << sym << std::endl);
+ gkey = GHOST_kKeyUnknown;
+ }
+#undef GXMAP
+ }
+
+ return gkey;
+}
+
+static const int default_cursor_size = 24;
+
+static const std::unordered_map<GHOST_TStandardCursor, std::string> cursors = {
+ {GHOST_kStandardCursorDefault, "left_ptr"},
+ {GHOST_kStandardCursorRightArrow, "right_ptr"},
+ {GHOST_kStandardCursorLeftArrow, "left_ptr"},
+ {GHOST_kStandardCursorInfo, ""},
+ {GHOST_kStandardCursorDestroy, ""},
+ {GHOST_kStandardCursorHelp, "question_arrow"},
+ {GHOST_kStandardCursorWait, "watch"},
+ {GHOST_kStandardCursorText, "xterm"},
+ {GHOST_kStandardCursorCrosshair, "crosshair"},
+ {GHOST_kStandardCursorCrosshairA, ""},
+ {GHOST_kStandardCursorCrosshairB, ""},
+ {GHOST_kStandardCursorCrosshairC, ""},
+ {GHOST_kStandardCursorPencil, ""},
+ {GHOST_kStandardCursorUpArrow, "sb_up_arrow"},
+ {GHOST_kStandardCursorDownArrow, "sb_down_arrow"},
+ {GHOST_kStandardCursorVerticalSplit, ""},
+ {GHOST_kStandardCursorHorizontalSplit, ""},
+ {GHOST_kStandardCursorEraser, ""},
+ {GHOST_kStandardCursorKnife, ""},
+ {GHOST_kStandardCursorEyedropper, ""},
+ {GHOST_kStandardCursorZoomIn, ""},
+ {GHOST_kStandardCursorZoomOut, ""},
+ {GHOST_kStandardCursorMove, "move"},
+ {GHOST_kStandardCursorNSEWScroll, ""},
+ {GHOST_kStandardCursorNSScroll, ""},
+ {GHOST_kStandardCursorEWScroll, ""},
+ {GHOST_kStandardCursorStop, ""},
+ {GHOST_kStandardCursorUpDown, "sb_v_double_arrow"},
+ {GHOST_kStandardCursorLeftRight, "sb_h_double_arrow"},
+ {GHOST_kStandardCursorTopSide, "top_side"},
+ {GHOST_kStandardCursorBottomSide, "bottom_side"},
+ {GHOST_kStandardCursorLeftSide, "left_side"},
+ {GHOST_kStandardCursorRightSide, "right_side"},
+ {GHOST_kStandardCursorTopLeftCorner, "top_left_corner"},
+ {GHOST_kStandardCursorTopRightCorner, "top_right_corner"},
+ {GHOST_kStandardCursorBottomRightCorner, "bottom_right_corner"},
+ {GHOST_kStandardCursorBottomLeftCorner, "bottom_left_corner"},
+ {GHOST_kStandardCursorCopy, "copy"},
+};
+
+static constexpr const char *mime_text_plain = "text/plain";
+static constexpr const char *mime_text_utf8 = "text/plain;charset=utf-8";
+static constexpr const char *mime_text_uri = "text/uri-list";
+
+static const std::unordered_map<std::string, GHOST_TDragnDropTypes> mime_dnd = {
+ {mime_text_plain, GHOST_kDragnDropTypeString},
+ {mime_text_utf8, GHOST_kDragnDropTypeString},
+ {mime_text_uri, GHOST_kDragnDropTypeFilenames},
+};
+
+static const std::vector<std::string> mime_preference_order = {
+ mime_text_uri,
+ mime_text_utf8,
+ mime_text_plain,
+};
+
+static const std::vector<std::string> mime_send = {
+ "UTF8_STRING",
+ "COMPOUND_TEXT",
+ "TEXT",
+ "STRING",
+ "text/plain;charset=utf-8",
+ "text/plain",
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Interface Callbacks
+ *
+ * These callbacks are registered for Wayland interfaces and called when
+ * an event is received from the compositor.
+ * \{ */
+
+static void relative_pointer_relative_motion(
+ void *data,
+ struct zwp_relative_pointer_v1 * /*zwp_relative_pointer_v1*/,
+ uint32_t /*utime_hi*/,
+ uint32_t /*utime_lo*/,
+ wl_fixed_t dx,
+ wl_fixed_t dy,
+ wl_fixed_t /*dx_unaccel*/,
+ wl_fixed_t /*dy_unaccel*/)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ input->x += wl_fixed_to_int(dx);
+ input->y += wl_fixed_to_int(dy);
+
+ input->system->pushEvent(
+ new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ input->system->getWindowManager()->getActiveWindow(),
+ input->x,
+ input->y,
+ GHOST_TABLET_DATA_NONE));
+}
+
+static const zwp_relative_pointer_v1_listener relative_pointer_listener = {
+ relative_pointer_relative_motion};
+
+static void dnd_events(const input_t *const input, const GHOST_TEventType event)
+{
+ const GHOST_TUns64 time = input->system->getMilliSeconds();
+ GHOST_IWindow *const window = input->system->getWindowManager()->getActiveWindow();
+ for (const std::string &type : mime_preference_order) {
+ input->system->pushEvent(new GHOST_EventDragnDrop(time,
+ event,
+ mime_dnd.at(type),
+ window,
+ input->data_offer_dnd->dnd.x,
+ input->data_offer_dnd->dnd.y,
+ nullptr));
+ }
+}
+
+static std::string read_pipe(data_offer_t *data_offer, const std::string mime_receive)
+{
+ int pipefd[2];
+ pipe(pipefd);
+ wl_data_offer_receive(data_offer->id, mime_receive.c_str(), pipefd[1]);
+ close(pipefd[1]);
+
+ std::string data;
+ ssize_t len;
+ char buffer[4096];
+ while ((len = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
+ data.insert(data.end(), buffer, buffer + len);
+ }
+ close(pipefd[0]);
+ data_offer->in_use.store(false);
+
+ return data;
+}
+
+/**
+ * A target accepts an offered mime type.
+ *
+ * Sent when a target accepts pointer_focus or motion events. If
+ * a target does not accept any of the offered types, type is NULL.
+ */
+static void data_source_target(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ const char * /*mime_type*/)
+{
+ /* pass */
+}
+
+static void data_source_send(void *data,
+ struct wl_data_source * /*wl_data_source*/,
+ const char * /*mime_type*/,
+ int32_t fd)
+{
+ const char *const buffer = static_cast<char *>(data);
+ write(fd, buffer, strlen(buffer) + 1);
+ close(fd);
+}
+
+static void data_source_cancelled(void * /*data*/, struct wl_data_source *wl_data_source)
+{
+ wl_data_source_destroy(wl_data_source);
+}
+
+/**
+ * The drag-and-drop operation physically finished.
+ *
+ * The user performed the drop action. This event does not
+ * indicate acceptance, #wl_data_source.cancelled may still be
+ * emitted afterwards if the drop destination does not accept any mime type.
+ */
+static void data_source_dnd_drop_performed(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/)
+{
+ /* pass */
+}
+
+/**
+ * The drag-and-drop operation concluded.
+ *
+ * The drop destination finished interoperating with this data
+ * source, so the client is now free to destroy this data source
+ * and free all associated data.
+ */
+static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*wl_data_source*/)
+{
+ /* pass */
+}
+
+/**
+ * Notify the selected action.
+ *
+ * This event indicates the action selected by the compositor
+ * after matching the source/destination side actions. Only one
+ * action (or none) will be offered here.
+ */
+static void data_source_action(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ uint32_t /*dnd_action*/)
+{
+ /* pass */
+}
+
+static const struct wl_data_source_listener data_source_listener = {
+ data_source_target,
+ data_source_send,
+ data_source_cancelled,
+ data_source_dnd_drop_performed,
+ data_source_dnd_finished,
+ data_source_action,
+};
+
+static void data_offer_offer(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ const char *mime_type)
+{
+ static_cast<data_offer_t *>(data)->types.insert(mime_type);
+}
+
+static void data_offer_source_actions(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ uint32_t source_actions)
+{
+ static_cast<data_offer_t *>(data)->source_actions = source_actions;
+}
+
+static void data_offer_action(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ uint32_t dnd_action)
+{
+ static_cast<data_offer_t *>(data)->dnd_action = dnd_action;
+}
+
+static const struct wl_data_offer_listener data_offer_listener = {
+ data_offer_offer,
+ data_offer_source_actions,
+ data_offer_action,
+};
+
+static void data_device_data_offer(void * /*data*/,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
+{
+ data_offer_t *data_offer = new data_offer_t;
+ data_offer->id = id;
+ wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
+}
+
+static void data_device_enter(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ uint32_t serial,
+ struct wl_surface * /*surface*/,
+ wl_fixed_t x,
+ wl_fixed_t y,
+ struct wl_data_offer *id)
+{
+ input_t *input = static_cast<input_t *>(data);
+ input->data_offer_dnd = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id));
+ data_offer_t *data_offer = input->data_offer_dnd;
+
+ data_offer->in_use.store(true);
+ data_offer->dnd.x = wl_fixed_to_int(x);
+ data_offer->dnd.y = wl_fixed_to_int(y);
+
+ wl_data_offer_set_actions(id,
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE,
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
+
+ for (const std::string &type : mime_preference_order) {
+ wl_data_offer_accept(id, serial, type.c_str());
+ }
+
+ dnd_events(input, GHOST_kEventDraggingEntered);
+}
+
+static void data_device_leave(void *data, struct wl_data_device * /*wl_data_device*/)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ dnd_events(input, GHOST_kEventDraggingExited);
+
+ if (input->data_offer_dnd && !input->data_offer_dnd->in_use.load()) {
+ wl_data_offer_destroy(input->data_offer_dnd->id);
+ delete input->data_offer_dnd;
+ input->data_offer_dnd = nullptr;
+ }
+}
+
+static void data_device_motion(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ uint32_t /*time*/,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ input_t *input = static_cast<input_t *>(data);
+ input->data_offer_dnd->dnd.x = wl_fixed_to_int(x);
+ input->data_offer_dnd->dnd.y = wl_fixed_to_int(y);
+ dnd_events(input, GHOST_kEventDraggingUpdated);
+}
+
+static void data_device_drop(void *data, struct wl_data_device * /*wl_data_device*/)
+{
+ input_t *input = static_cast<input_t *>(data);
+ data_offer_t *data_offer = input->data_offer_dnd;
+
+ const std::string mime_receive = *std::find_first_of(mime_preference_order.begin(),
+ mime_preference_order.end(),
+ data_offer->types.begin(),
+ data_offer->types.end());
+
+ auto read_uris = [](GHOST_SystemWayland *const system,
+ data_offer_t *data_offer,
+ const std::string mime_receive) {
+ const int x = data_offer->dnd.x;
+ const int y = data_offer->dnd.y;
+
+ const std::string data = read_pipe(data_offer, mime_receive);
+
+ wl_data_offer_finish(data_offer->id);
+ wl_data_offer_destroy(data_offer->id);
+
+ delete data_offer;
+ data_offer = nullptr;
+
+ if (mime_receive == mime_text_uri) {
+ static constexpr const char *file_proto = "file://";
+ static constexpr const char *crlf = "\r\n";
+
+ std::vector<std::string> uris;
+
+ size_t pos = 0;
+ while (true) {
+ pos = data.find(file_proto, pos);
+ const size_t start = pos + sizeof(file_proto) - 1;
+ pos = data.find(crlf, pos);
+ const size_t end = pos;
+
+ if (pos == std::string::npos) {
+ break;
+ }
+ uris.push_back(data.substr(start, end - start));
+ }
+
+ GHOST_TStringArray *flist = static_cast<GHOST_TStringArray *>(
+ malloc(sizeof(GHOST_TStringArray)));
+ flist->count = int(uris.size());
+ flist->strings = static_cast<GHOST_TUns8 **>(malloc(uris.size() * sizeof(GHOST_TUns8 *)));
+ for (size_t i = 0; i < uris.size(); i++) {
+ flist->strings[i] = static_cast<GHOST_TUns8 *>(
+ malloc((uris[i].size() + 1) * sizeof(GHOST_TUns8)));
+ memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1);
+ }
+ system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
+ GHOST_kEventDraggingDropDone,
+ GHOST_kDragnDropTypeFilenames,
+ system->getWindowManager()->getActiveWindow(),
+ x,
+ y,
+ flist));
+ }
+ else if (mime_receive == mime_text_plain || mime_receive == mime_text_utf8) {
+ /* TODO: enable use of internal functions 'txt_insert_buf' and
+ * 'text_update_edited' to behave like dropped text was pasted. */
+ }
+ wl_display_roundtrip(system->display());
+ };
+
+ std::thread read_thread(read_uris, input->system, data_offer, mime_receive);
+ read_thread.detach();
+}
+
+static void data_device_selection(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
+{
+ input_t *input = static_cast<input_t *>(data);
+ data_offer_t *data_offer = input->data_offer_copy_paste;
+
+ /* Delete old data offer. */
+ if (data_offer != nullptr) {
+ wl_data_offer_destroy(data_offer->id);
+ delete data_offer;
+ data_offer = nullptr;
+ }
+
+ if (id == nullptr) {
+ return;
+ }
+
+ /* Get new data offer. */
+ data_offer = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id));
+ input->data_offer_copy_paste = data_offer;
+
+ std::string mime_receive;
+ for (const std::string &type : {mime_text_utf8, mime_text_plain}) {
+ if (data_offer->types.count(type)) {
+ mime_receive = type;
+ break;
+ }
+ }
+
+ auto read_selection = [](GHOST_SystemWayland *const system,
+ data_offer_t *data_offer,
+ const std::string mime_receive) {
+ const std::string data = read_pipe(data_offer, mime_receive);
+ system->setSelection(data);
+ };
+
+ std::thread read_thread(read_selection, input->system, data_offer, mime_receive);
+ read_thread.detach();
+}
+
+static const struct wl_data_device_listener data_device_listener = {
+ data_device_data_offer,
+ data_device_enter,
+ data_device_leave,
+ data_device_motion,
+ data_device_drop,
+ data_device_selection,
+};
+
+static void buffer_release(void * /*data*/, struct wl_buffer *wl_buffer)
+{
+ wl_buffer_destroy(wl_buffer);
+}
+
+const struct wl_buffer_listener buffer_listener = {
+ buffer_release,
+};
+
+static void pointer_enter(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t serial,
+ struct wl_surface *surface,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
+{
+ if (!surface) {
+ return;
+ }
+ input_t *input = static_cast<input_t *>(data);
+ input->pointer_serial = serial;
+ input->x = wl_fixed_to_int(surface_x);
+ input->y = wl_fixed_to_int(surface_y);
+
+ static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface))->activate();
+}
+
+static void pointer_leave(void * /*data*/,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*serial*/,
+ struct wl_surface *surface)
+{
+ if (surface != nullptr) {
+ static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface))->deactivate();
+ }
+}
+
+static void pointer_motion(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*time*/,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ input->x = wl_fixed_to_int(surface_x);
+ input->y = wl_fixed_to_int(surface_y);
+
+ input->system->pushEvent(
+ new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ input->system->getWindowManager()->getActiveWindow(),
+ wl_fixed_to_int(surface_x),
+ wl_fixed_to_int(surface_y),
+ GHOST_TABLET_DATA_NONE));
+}
+
+static void pointer_button(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t serial,
+ uint32_t /*time*/,
+ uint32_t button,
+ uint32_t state)
+{
+ GHOST_TEventType etype = GHOST_kEventUnknown;
+ switch (state) {
+ case WL_POINTER_BUTTON_STATE_RELEASED:
+ etype = GHOST_kEventButtonUp;
+ break;
+ case WL_POINTER_BUTTON_STATE_PRESSED:
+ etype = GHOST_kEventButtonDown;
+ break;
+ }
+
+ GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft;
+ switch (button) {
+ case BTN_LEFT:
+ ebutton = GHOST_kButtonMaskLeft;
+ break;
+ case BTN_MIDDLE:
+ ebutton = GHOST_kButtonMaskMiddle;
+ break;
+ case BTN_RIGHT:
+ ebutton = GHOST_kButtonMaskRight;
+ break;
+ }
+
+ input_t *input = static_cast<input_t *>(data);
+ input->data_source->source_serial = serial;
+ input->buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
+ input->system->pushEvent(
+ new GHOST_EventButton(input->system->getMilliSeconds(),
+ etype,
+ input->system->getWindowManager()->getActiveWindow(),
+ ebutton,
+ GHOST_TABLET_DATA_NONE));
+}
+
+static void pointer_axis(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*time*/,
+ uint32_t axis,
+ wl_fixed_t value)
+{
+ if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ return;
+ }
+ input_t *input = static_cast<input_t *>(data);
+ input->system->pushEvent(
+ new GHOST_EventWheel(input->system->getMilliSeconds(),
+ input->system->getWindowManager()->getActiveWindow(),
+ std::signbit(value) ? +1 : -1));
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+ pointer_enter,
+ pointer_leave,
+ pointer_motion,
+ pointer_button,
+ pointer_axis,
+};
+
+static void keyboard_keymap(
+ void *data, struct wl_keyboard * /*wl_keyboard*/, uint32_t format, int32_t fd, uint32_t size)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ if ((!data) || (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)) {
+ close(fd);
+ return;
+ }
+
+ char *map_str = static_cast<char *>(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0));
+ if (map_str == MAP_FAILED) {
+ close(fd);
+ throw std::runtime_error("keymap mmap failed: " + std::string(std::strerror(errno)));
+ }
+
+ struct xkb_keymap *keymap = xkb_keymap_new_from_string(
+ input->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
+ munmap(map_str, size);
+ close(fd);
+
+ if (!keymap) {
+ return;
+ }
+
+ input->xkb_state = xkb_state_new(keymap);
+
+ xkb_keymap_unref(keymap);
+}
+
+/**
+ * Enter event.
+ *
+ * Notification that this seat's keyboard focus is on a certain
+ * surface.
+ */
+static void keyboard_enter(void * /*data*/,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ struct wl_surface * /*surface*/,
+ struct wl_array * /*keys*/)
+{
+ /* pass */
+}
+
+/**
+ * Leave event.
+ *
+ * Notification that this seat's keyboard focus is no longer on a
+ * certain surface.
+ */
+static void keyboard_leave(void * /*data*/,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ struct wl_surface * /*surface*/)
+{
+ /* pass */
+}
+
+static void keyboard_key(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t serial,
+ uint32_t /*time*/,
+ uint32_t key,
+ uint32_t state)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ GHOST_TEventType etype = GHOST_kEventUnknown;
+ switch (state) {
+ case WL_KEYBOARD_KEY_STATE_RELEASED:
+ etype = GHOST_kEventKeyUp;
+ break;
+ case WL_KEYBOARD_KEY_STATE_PRESSED:
+ etype = GHOST_kEventKeyDown;
+ break;
+ }
+
+ const xkb_keysym_t sym = xkb_state_key_get_one_sym(input->xkb_state, key + 8);
+ if (sym == XKB_KEY_NoSymbol) {
+ return;
+ }
+ const GHOST_TKey gkey = xkb_map_gkey(sym);
+
+ GHOST_TEventKeyData key_data;
+
+ if (etype == GHOST_kEventKeyDown) {
+ xkb_state_key_get_utf8(
+ input->xkb_state, key + 8, key_data.utf8_buf, sizeof(GHOST_TEventKeyData::utf8_buf));
+ }
+ else {
+ key_data.utf8_buf[0] = '\0';
+ }
+
+ input->data_source->source_serial = serial;
+ input->system->pushEvent(new GHOST_EventKey(input->system->getMilliSeconds(),
+ etype,
+ input->system->getWindowManager()->getActiveWindow(),
+ gkey,
+ '\0',
+ key_data.utf8_buf,
+ false));
+}
+
+static void keyboard_modifiers(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ uint32_t mods_depressed,
+ uint32_t mods_latched,
+ uint32_t mods_locked,
+ uint32_t group)
+{
+ xkb_state_update_mask(static_cast<input_t *>(data)->xkb_state,
+ mods_depressed,
+ mods_latched,
+ mods_locked,
+ 0,
+ 0,
+ group);
+}
+
+static const struct wl_keyboard_listener keyboard_listener = {
+ keyboard_keymap,
+ keyboard_enter,
+ keyboard_leave,
+ keyboard_key,
+ keyboard_modifiers,
+};
+
+static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
+{
+ input_t *input = static_cast<input_t *>(data);
+ input->pointer = nullptr;
+ input->keyboard = nullptr;
+
+ if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
+ input->pointer = wl_seat_get_pointer(wl_seat);
+ input->cursor.surface = wl_compositor_create_surface(input->system->compositor());
+ input->cursor.visible = true;
+ input->cursor.buffer = nullptr;
+ input->cursor.file_buffer = new buffer_t;
+ wl_pointer_add_listener(input->pointer, &pointer_listener, data);
+ }
+
+ if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
+ input->keyboard = wl_seat_get_keyboard(wl_seat);
+ wl_keyboard_add_listener(input->keyboard, &keyboard_listener, data);
+ }
+}
+
+static void seat_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
+{
+ static_cast<input_t *>(data)->name = std::string(name);
+}
+
+static const struct wl_seat_listener seat_listener = {
+ seat_capabilities,
+ seat_name,
+};
+
+static void output_geometry(void *data,
+ struct wl_output * /*wl_output*/,
+ int32_t /*x*/,
+ int32_t /*y*/,
+ int32_t /*physical_width*/,
+ int32_t /*physical_height*/,
+ int32_t /*subpixel*/,
+ const char *make,
+ const char *model,
+ int32_t transform)
+{
+ output_t *output = static_cast<output_t *>(data);
+ output->transform = transform;
+ output->make = std::string(make);
+ output->model = std::string(model);
+}
+
+static void output_mode(void *data,
+ struct wl_output * /*wl_output*/,
+ uint32_t /*flags*/,
+ int32_t width,
+ int32_t height,
+ int32_t /*refresh*/)
+{
+ output_t *output = static_cast<output_t *>(data);
+ output->width = width;
+ output->height = height;
+}
+
+/**
+ * Sent all information about output.
+ *
+ * This event is sent after all other properties have been sent
+ * after binding to the output object and after any other property
+ * changes done after that. This allows changes to the output
+ * properties to be seen as atomic, even if they happen via multiple events.
+ */
+static void output_done(void * /*data*/, struct wl_output * /*wl_output*/)
+{
+}
+
+static void output_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor)
+{
+ static_cast<output_t *>(data)->scale = factor;
+}
+
+static const struct wl_output_listener output_listener = {
+ output_geometry,
+ output_mode,
+ output_done,
+ output_scale,
+};
+
+static void shell_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
+{
+ xdg_wm_base_pong(xdg_wm_base, serial);
+}
+
+static const struct xdg_wm_base_listener shell_listener = {
+ shell_ping,
+};
+
+static void global_add(void *data,
+ struct wl_registry *wl_registry,
+ uint32_t name,
+ const char *interface,
+ uint32_t /*version*/)
+{
+ struct display_t *display = static_cast<struct display_t *>(data);
+ if (!strcmp(interface, wl_compositor_interface.name)) {
+ display->compositor = static_cast<wl_compositor *>(
+ wl_registry_bind(wl_registry, name, &wl_compositor_interface, 1));
+ }
+ else if (!strcmp(interface, xdg_wm_base_interface.name)) {
+ display->xdg_shell = static_cast<xdg_wm_base *>(
+ wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1));
+ xdg_wm_base_add_listener(display->xdg_shell, &shell_listener, nullptr);
+ }
+ else if (!strcmp(interface, wl_output_interface.name)) {
+ output_t *output = new output_t;
+ output->scale = 1;
+ output->output = static_cast<wl_output *>(
+ wl_registry_bind(wl_registry, name, &wl_output_interface, 2));
+ display->outputs.push_back(output);
+ wl_output_add_listener(output->output, &output_listener, output);
+ }
+ else if (!strcmp(interface, wl_seat_interface.name)) {
+ input_t *input = new input_t;
+ input->system = display->system;
+ input->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ input->xkb_state = nullptr;
+ input->data_offer_dnd = nullptr;
+ input->data_offer_copy_paste = nullptr;
+ input->data_source = new data_source_t;
+ input->data_source->data_source = nullptr;
+ input->data_source->buffer_out = nullptr;
+ input->relative_pointer = nullptr;
+ input->locked_pointer = nullptr;
+ input->seat = static_cast<wl_seat *>(
+ wl_registry_bind(wl_registry, name, &wl_seat_interface, 2));
+ display->inputs.push_back(input);
+ wl_seat_add_listener(input->seat, &seat_listener, input);
+ }
+ else if (!strcmp(interface, wl_shm_interface.name)) {
+ display->shm = static_cast<wl_shm *>(
+ wl_registry_bind(wl_registry, name, &wl_shm_interface, 1));
+ }
+ else if (!strcmp(interface, wl_data_device_manager_interface.name)) {
+ display->data_device_manager = static_cast<wl_data_device_manager *>(
+ wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 1));
+ }
+ else if (!strcmp(interface, zwp_relative_pointer_manager_v1_interface.name)) {
+ display->relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>(
+ wl_registry_bind(wl_registry, name, &zwp_relative_pointer_manager_v1_interface, 1));
+ }
+ else if (!strcmp(interface, zwp_pointer_constraints_v1_interface.name)) {
+ display->pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>(
+ wl_registry_bind(wl_registry, name, &zwp_pointer_constraints_v1_interface, 1));
+ }
+}
+
+/**
+ * Announce removal of global object.
+ *
+ * Notify the client of removed global objects.
+ *
+ * This event notifies the client that the global identified by
+ * name is no longer available. If the client bound to the global
+ * using the bind request, the client should now destroy that object.
+ */
+static void global_remove(void * /*data*/, struct wl_registry * /*wl_registry*/, uint32_t /*name*/)
+{
+}
+
+static const struct wl_registry_listener registry_listener = {
+ global_add,
+ global_remove,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Ghost Implementation
+ *
+ * Wayland specific implementation of the GHOST_System interface.
+ * \{ */
+
+GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t)
+{
+ d->system = this;
+ /* Connect to the Wayland server. */
+ d->display = wl_display_connect(nullptr);
+ if (!d->display) {
+ display_destroy(d);
+ throw std::runtime_error("Wayland: unable to connect to display!");
+ }
+
+ /* Register interfaces. */
+ struct wl_registry *registry = wl_display_get_registry(d->display);
+ wl_registry_add_listener(registry, &registry_listener, d);
+ /* Call callback for registry listener. */
+ wl_display_roundtrip(d->display);
+ /* Call callbacks for registered listeners. */
+ wl_display_roundtrip(d->display);
+ wl_registry_destroy(registry);
+
+ if (!d->xdg_shell) {
+ display_destroy(d);
+ throw std::runtime_error("Wayland: unable to access xdg_shell!");
+ }
+
+ /* Register data device per seat for IPC between Wayland clients. */
+ if (d->data_device_manager) {
+ for (input_t *input : d->inputs) {
+ input->data_device = wl_data_device_manager_get_data_device(d->data_device_manager,
+ input->seat);
+ wl_data_device_add_listener(input->data_device, &data_device_listener, input);
+ }
+ }
+
+ const char *theme = std::getenv("XCURSOR_THEME");
+ const char *size = std::getenv("XCURSOR_SIZE");
+ const int sizei = size ? std::stoi(size) : default_cursor_size;
+
+ d->cursor_theme = wl_cursor_theme_load(theme, sizei, d->shm);
+ if (!d->cursor_theme) {
+ display_destroy(d);
+ throw std::runtime_error("Wayland: unable to access cursor themes!");
+ }
+}
+
+GHOST_SystemWayland::~GHOST_SystemWayland()
+{
+ display_destroy(d);
+}
+
+bool GHOST_SystemWayland::processEvents(bool /*waitForEvent*/)
+{
+ wl_display_dispatch(d->display);
+ return true;
+}
+
+int GHOST_SystemWayland::toggleConsole(int /*action*/)
+{
+ return 0;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const
+{
+ if (!d->inputs.empty()) {
+ static const xkb_state_component mods_all = xkb_state_component(
+ XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_MODS_LOCKED |
+ XKB_STATE_MODS_EFFECTIVE);
+
+ keys.set(GHOST_kModifierKeyLeftShift,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) ==
+ 1);
+ keys.set(GHOST_kModifierKeyRightShift,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) ==
+ 1);
+ keys.set(GHOST_kModifierKeyLeftAlt,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LAlt", mods_all) == 1);
+ keys.set(GHOST_kModifierKeyRightAlt,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RAlt", mods_all) == 1);
+ keys.set(GHOST_kModifierKeyLeftControl,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LControl", mods_all) == 1);
+ keys.set(GHOST_kModifierKeyRightControl,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RControl", mods_all) == 1);
+ keys.set(GHOST_kModifierKeyOS,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "Super", mods_all) == 1);
+ keys.set(GHOST_kModifierKeyNumMasks,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "NumLock", mods_all) == 1);
+
+ return GHOST_kSuccess;
+ }
+ return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const
+{
+ if (!d->inputs.empty()) {
+ buttons = d->inputs[0]->buttons;
+ return GHOST_kSuccess;
+ }
+ return GHOST_kFailure;
+}
+
+GHOST_TUns8 *GHOST_SystemWayland::getClipboard(bool /*selection*/) const
+{
+ GHOST_TUns8 *clipboard = static_cast<GHOST_TUns8 *>(malloc((selection.size() + 1)));
+ memcpy(clipboard, selection.data(), selection.size() + 1);
+ return clipboard;
+}
+
+void GHOST_SystemWayland::putClipboard(GHOST_TInt8 *buffer, bool /*selection*/) const
+{
+ if (!d->data_device_manager || d->inputs.empty()) {
+ return;
+ }
+
+ data_source_t *data_source = d->inputs[0]->data_source;
+
+ /* Copy buffer. */
+ data_source->buffer_out = static_cast<char *>(malloc(strlen(buffer) + 1));
+ std::strcpy(data_source->buffer_out, buffer);
+
+ data_source->data_source = wl_data_device_manager_create_data_source(d->data_device_manager);
+
+ wl_data_source_add_listener(
+ data_source->data_source, &data_source_listener, data_source->buffer_out);
+
+ for (const std::string &type : mime_send) {
+ wl_data_source_offer(data_source->data_source, type.c_str());
+ }
+
+ if (!d->inputs.empty() && d->inputs[0]->data_device) {
+ wl_data_device_set_selection(
+ d->inputs[0]->data_device, data_source->data_source, data_source->source_serial);
+ }
+}
+
+GHOST_TUns8 GHOST_SystemWayland::getNumDisplays() const
+{
+ return d ? GHOST_TUns8(d->outputs.size()) : 0;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const
+{
+ if (getWindowManager()->getActiveWindow() != nullptr && !d->inputs.empty()) {
+ x = d->inputs[0]->x;
+ y = d->inputs[0]->y;
+ return GHOST_kSuccess;
+ }
+ else {
+ return GHOST_kFailure;
+ }
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(GHOST_TInt32 /*x*/, GHOST_TInt32 /*y*/)
+{
+ return GHOST_kFailure;
+}
+
+void GHOST_SystemWayland::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
+{
+ if (getNumDisplays() > 0) {
+ /* We assume first output as main. */
+ width = uint32_t(d->outputs[0]->width);
+ height = uint32_t(d->outputs[0]->height);
+ }
+}
+
+void GHOST_SystemWayland::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
+{
+ getMainDisplayDimensions(width, height);
+}
+
+GHOST_IContext *GHOST_SystemWayland::createOffscreenContext()
+{
+ /* Create new off-screen window. */
+ wl_surface *os_surface = wl_compositor_create_surface(compositor());
+ wl_egl_window *os_egl_window = wl_egl_window_create(os_surface, int(1), int(1));
+
+ d->os_surfaces.push_back(os_surface);
+ d->os_egl_windows.push_back(os_egl_window);
+
+ GHOST_Context *context = new GHOST_ContextEGL(false,
+ EGLNativeWindowType(os_egl_window),
+ EGLNativeDisplayType(d->display),
+ EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
+ 3,
+ 3,
+ GHOST_OPENGL_EGL_CONTEXT_FLAGS,
+ GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
+ EGL_OPENGL_API);
+
+ if (context->initializeDrawingContext()) {
+ return context;
+ }
+ else {
+ delete context;
+ }
+
+ GHOST_PRINT("Cannot create off-screen EGL context" << std::endl);
+
+ return nullptr;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::disposeContext(GHOST_IContext *context)
+{
+ delete context;
+ return GHOST_kSuccess;
+}
+
+GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ GHOST_TDrawingContextType type,
+ GHOST_GLSettings glSettings,
+ const bool exclusive,
+ const bool /*is_dialog*/,
+ const GHOST_IWindow *parentWindow)
+{
+ GHOST_WindowWayland *window = new GHOST_WindowWayland(
+ this,
+ title,
+ left,
+ top,
+ width,
+ height,
+ state,
+ parentWindow,
+ type,
+ ((glSettings.flags & GHOST_glStereoVisual) != 0),
+ exclusive);
+
+ if (window) {
+ if (window->getValid()) {
+ m_windowManager->addWindow(window);
+ m_windowManager->setActiveWindow(window);
+ pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
+ }
+ else {
+ delete window;
+ window = nullptr;
+ }
+ }
+
+ return window;
+}
+
+wl_display *GHOST_SystemWayland::display()
+{
+ return d->display;
+}
+
+wl_compositor *GHOST_SystemWayland::compositor()
+{
+ return d->compositor;
+}
+
+xdg_wm_base *GHOST_SystemWayland::shell()
+{
+ return d->xdg_shell;
+}
+
+void GHOST_SystemWayland::setSelection(const std::string &selection)
+{
+ this->selection = selection;
+}
+
+static void set_cursor_buffer(input_t *input, wl_buffer *buffer)
+{
+ input->cursor.visible = (buffer != nullptr);
+
+ wl_surface_attach(input->cursor.surface, buffer, 0, 0);
+ wl_surface_commit(input->cursor.surface);
+
+ if (input->cursor.visible) {
+ wl_surface_damage(input->cursor.surface,
+ 0,
+ 0,
+ int32_t(input->cursor.image.width),
+ int32_t(input->cursor.image.height));
+ wl_pointer_set_cursor(input->pointer,
+ input->pointer_serial,
+ input->cursor.surface,
+ int32_t(input->cursor.image.hotspot_x),
+ int32_t(input->cursor.image.hotspot_y));
+ }
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
+{
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
+ }
+ const std::string cursor_name = cursors.count(shape) ? cursors.at(shape) :
+ cursors.at(GHOST_kStandardCursorDefault);
+
+ wl_cursor *cursor = wl_cursor_theme_get_cursor(d->cursor_theme, cursor_name.c_str());
+
+ if (!cursor) {
+ GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
+ return GHOST_kFailure;
+ }
+
+ struct wl_cursor_image *image = cursor->images[0];
+ struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
+ if (!buffer) {
+ return GHOST_kFailure;
+ }
+ cursor_t *c = &d->inputs[0]->cursor;
+ c->buffer = buffer;
+ c->image = *image;
+
+ set_cursor_buffer(d->inputs[0], buffer);
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
+{
+ return GHOST_TSuccess(cursors.count(cursorShape) && !cursors.at(cursorShape).empty());
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(GHOST_TUns8 *bitmap,
+ GHOST_TUns8 *mask,
+ int sizex,
+ int sizey,
+ int hotX,
+ int hotY,
+ bool /*canInvertColor*/)
+{
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
+ }
+
+ cursor_t *cursor = &d->inputs[0]->cursor;
+
+ static const int32_t stride = sizex * 4; /* ARGB */
+ cursor->file_buffer->size = size_t(stride * sizey);
+
+ const int fd = memfd_create("blender-cursor-custom", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
+ posix_fallocate(fd, 0, int32_t(cursor->file_buffer->size));
+
+ cursor->file_buffer->data = mmap(
+ nullptr, cursor->file_buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ struct wl_shm_pool *pool = wl_shm_create_pool(d->shm, fd, int32_t(cursor->file_buffer->size));
+
+ wl_buffer *buffer = wl_shm_pool_create_buffer(
+ pool, 0, sizex, sizey, stride, WL_SHM_FORMAT_ARGB8888);
+
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ wl_buffer_add_listener(buffer, &buffer_listener, nullptr);
+
+ static constexpr uint32_t black = 0xFF000000;
+ static constexpr uint32_t white = 0xFFFFFFFF;
+ static constexpr uint32_t transparent = 0x00000000;
+
+ uint8_t datab = 0, maskb = 0;
+ uint32_t *pixel;
+
+ for (int y = 0; y < sizey; ++y) {
+ pixel = &static_cast<uint32_t *>(cursor->file_buffer->data)[y * sizex];
+ for (int x = 0; x < sizex; ++x) {
+ if ((x % 8) == 0) {
+ datab = *bitmap++;
+ maskb = *mask++;
+
+ /* Reverse bit order. */
+ datab = uint8_t((datab * 0x0202020202ULL & 0x010884422010ULL) % 1023);
+ maskb = uint8_t((maskb * 0x0202020202ULL & 0x010884422010ULL) % 1023);
+ }
+
+ if (maskb & 0x80) {
+ *pixel++ = (datab & 0x80) ? white : black;
+ }
+ else {
+ *pixel++ = (datab & 0x80) ? white : transparent;
+ }
+ datab <<= 1;
+ maskb <<= 1;
+ }
+ }
+
+ cursor->buffer = buffer;
+ cursor->image.width = uint32_t(sizex);
+ cursor->image.height = uint32_t(sizey);
+ cursor->image.hotspot_x = uint32_t(hotX);
+ cursor->image.hotspot_y = uint32_t(hotY);
+
+ set_cursor_buffer(d->inputs[0], buffer);
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
+{
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
+ }
+
+ cursor_t *cursor = &d->inputs[0]->cursor;
+ if (visible) {
+ if (!cursor->visible) {
+ set_cursor_buffer(d->inputs[0], d->inputs[0]->cursor.buffer);
+ }
+ }
+ else {
+ if (cursor->visible) {
+ set_cursor_buffer(d->inputs[0], nullptr);
+ }
+ }
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
+ wl_surface *surface)
+{
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
+ }
+
+ input_t *input = d->inputs[0];
+
+ switch (mode) {
+ case GHOST_kGrabDisable:
+ if (input->relative_pointer) {
+ zwp_relative_pointer_v1_destroy(input->relative_pointer);
+ input->relative_pointer = nullptr;
+ }
+ if (input->locked_pointer) {
+ zwp_locked_pointer_v1_destroy(input->locked_pointer);
+ input->locked_pointer = nullptr;
+ }
+ break;
+
+ case GHOST_kGrabNormal:
+ case GHOST_kGrabWrap:
+ input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
+ d->relative_pointer_manager, input->pointer);
+ zwp_relative_pointer_v1_add_listener(
+ input->relative_pointer, &relative_pointer_listener, input);
+ input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
+ d->pointer_constraints,
+ surface,
+ input->pointer,
+ nullptr,
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ break;
+
+ case GHOST_kGrabHide:
+ setCursorVisibility(false);
+ break;
+ }
+
+ return GHOST_kSuccess;
+}
+
+/** \} */
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
new file mode 100644
index 00000000000..89cd3406b69
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -0,0 +1,111 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ * Declaration of GHOST_SystemWayland class.
+ */
+
+#ifndef __GHOST_SYSTEMWAYLAND_H__
+#define __GHOST_SYSTEMWAYLAND_H__
+
+#include "../GHOST_Types.h"
+#include "GHOST_System.h"
+#include "GHOST_WindowWayland.h"
+
+#include <wayland-client.h>
+#include <xdg-shell-client-protocol.h>
+
+#include <string>
+
+class GHOST_WindowWayland;
+
+struct display_t;
+
+class GHOST_SystemWayland : public GHOST_System {
+ public:
+ GHOST_SystemWayland();
+
+ ~GHOST_SystemWayland() override;
+
+ bool processEvents(bool waitForEvent) override;
+
+ int toggleConsole(int action) override;
+
+ GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const override;
+
+ GHOST_TSuccess getButtons(GHOST_Buttons &buttons) const override;
+
+ GHOST_TUns8 *getClipboard(bool selection) const override;
+
+ void putClipboard(GHOST_TInt8 *buffer, bool selection) const override;
+
+ GHOST_TUns8 getNumDisplays() const override;
+
+ GHOST_TSuccess getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const override;
+
+ GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) override;
+
+ void getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const override;
+
+ void getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const override;
+
+ GHOST_IContext *createOffscreenContext() override;
+
+ GHOST_TSuccess disposeContext(GHOST_IContext *context) override;
+
+ GHOST_IWindow *createWindow(const char *title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ GHOST_TDrawingContextType type,
+ GHOST_GLSettings glSettings,
+ const bool exclusive,
+ const bool is_dialog,
+ const GHOST_IWindow *parentWindow) override;
+
+ wl_display *display();
+
+ wl_compositor *compositor();
+
+ xdg_wm_base *shell();
+
+ void setSelection(const std::string &selection);
+
+ GHOST_TSuccess setCursorShape(GHOST_TStandardCursor shape);
+
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape);
+
+ GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap,
+ GHOST_TUns8 *mask,
+ int sizex,
+ int sizey,
+ int hotX,
+ int hotY,
+ bool canInvertColor);
+
+ GHOST_TSuccess setCursorVisibility(bool visible);
+
+ GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode, wl_surface *surface);
+
+ private:
+ struct display_t *d;
+ std::string selection;
+};
+
+#endif /* __GHOST_SYSTEMWAYLAND_H__ */
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index fdd022e44ac..849aa5a96f5 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -282,7 +282,7 @@ void GHOST_SystemWin32::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns3
height = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
}
-GHOST_IWindow *GHOST_SystemWin32::createWindow(const STR_String &title,
+GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index c6d810d2a38..b23f907608c 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -126,7 +126,7 @@ class GHOST_SystemWin32 : public GHOST_System {
* \param parentWindow Parent window
* \return The new window (or 0 if creation failed).
*/
- GHOST_IWindow *createWindow(const STR_String &title,
+ GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 825b93de36f..91c63a3fb76 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -338,7 +338,7 @@ void GHOST_SystemX11::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32
* \param parentWindow Parent window
* \return The new window (or 0 if creation failed).
*/
-GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title,
+GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -1881,7 +1881,7 @@ static GHOST_TKey ghost_key_from_keysym(const KeySym key)
# endif
#endif
default:
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
printf("%s: unknown key: %lu / 0x%lx\n", __func__, key, key);
#endif
type = GHOST_kKeyUnknown;
@@ -1905,7 +1905,7 @@ static GHOST_TKey ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCo
switch (id) {
case MAKE_ID('T', 'L', 'D', 'E'):
return GHOST_kKeyAccentGrave;
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
default:
printf("%s unhandled keycode: %.*s\n", __func__, XkbKeyNameLength, id_str);
break;
@@ -2456,7 +2456,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
string cmd = "xdg-open \"" + string(link) + "\"";
if (system(cmd.c_str()) != 0) {
GHOST_PRINTF("GHOST_SystemX11::showMessageBox: Unable to run system command [%s]",
- cmd);
+ cmd.c_str());
}
}
break;
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index d0e0506e77b..bb01ef7e0cc 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -137,7 +137,7 @@ class GHOST_SystemX11 : public GHOST_System {
* \param parentWindow Parent (embedder) window
* \return The new window (or 0 if creation failed).
*/
- GHOST_IWindow *createWindow(const STR_String &title,
+ GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 553a7d89df4..472149148e6 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -27,7 +27,6 @@
#include "GHOST_IWindow.h"
-class STR_String;
class GHOST_Context;
/**
@@ -61,8 +60,8 @@ class GHOST_Window : public GHOST_IWindow {
* \section Interface inherited from GHOST_IWindow left for derived class
* implementation.
* virtual bool getValid() const = 0;
- * virtual void setTitle(const STR_String& title) = 0;
- * virtual void getTitle(STR_String& title) const = 0;
+ * virtual void setTitle(const char * title) = 0;
+ * virtual std::string getTitle() const = 0;
* virtual void getWindowBounds(GHOST_Rect& bounds) const = 0;
* virtual void getClientBounds(GHOST_Rect& bounds) const = 0;
* virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0;
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index efa418deee2..15429eab5db 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -30,7 +30,6 @@
#endif // __APPLE__
#include "GHOST_Window.h"
-#include "STR_String.h"
@class CAMetalLayer;
@class CocoaMetalView;
@@ -58,7 +57,7 @@ class GHOST_WindowCocoa : public GHOST_Window {
* \param stereoVisual Stereo visual for quad buffered stereo.
*/
GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 bottom,
GHOST_TUns32 width,
@@ -92,13 +91,12 @@ class GHOST_WindowCocoa : public GHOST_Window {
* Sets the title displayed in the title bar.
* \param title The title to display in the title bar.
*/
- void setTitle(const STR_String &title);
-
+ void setTitle(const char *title);
/**
* Returns the title displayed in the title bar.
* \param title The title displayed in the title bar.
*/
- void getTitle(STR_String &title) const;
+ std::string getTitle() const;
/**
* Returns the window rectangle dimensions.
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 10ab05a0de1..05adc41cb8e 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -291,7 +291,7 @@
/* clang-format on */
GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 bottom,
GHOST_TUns32 width,
@@ -482,7 +482,7 @@ void *GHOST_WindowCocoa::getOSWindow() const
return (void *)m_window;
}
-void GHOST_WindowCocoa::setTitle(const STR_String &title)
+void GHOST_WindowCocoa::setTitle(const char *title)
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid");
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@@ -524,7 +524,7 @@ void GHOST_WindowCocoa::setTitle(const STR_String &title)
[pool drain];
}
-void GHOST_WindowCocoa::getTitle(STR_String &title) const
+std::string GHOST_WindowCocoa::getTitle() const
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid");
@@ -532,11 +532,14 @@ void GHOST_WindowCocoa::getTitle(STR_String &title) const
NSString *windowTitle = [m_window title];
+ std::string title;
if (windowTitle != nil) {
title = [windowTitle UTF8String];
}
[pool drain];
+
+ return title;
}
void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect &bounds) const
diff --git a/intern/ghost/intern/GHOST_WindowNULL.h b/intern/ghost/intern/GHOST_WindowNULL.h
index db40075e6ca..e1aa0cb7f13 100644
--- a/intern/ghost/intern/GHOST_WindowNULL.h
+++ b/intern/ghost/intern/GHOST_WindowNULL.h
@@ -26,7 +26,6 @@
#include <map>
-class STR_String;
class GHOST_SystemNULL;
class GHOST_WindowNULL : public GHOST_Window {
@@ -37,7 +36,7 @@ class GHOST_WindowNULL : public GHOST_Window {
}
GHOST_WindowNULL(GHOST_SystemNULL *system,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -83,12 +82,12 @@ class GHOST_WindowNULL : public GHOST_Window {
{
return true;
}
- void setTitle(const STR_String &title)
+ void setTitle(const char *title)
{ /* nothing */
}
- void getTitle(STR_String &title) const
+ std::string getTitle() const
{
- title = "untitled";
+ return "untitled";
}
void getWindowBounds(GHOST_Rect &bounds) const
{
diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp
index e8d129f45fe..dcb1ab8c78c 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.cpp
+++ b/intern/ghost/intern/GHOST_WindowSDL.cpp
@@ -27,7 +27,7 @@
#include <assert.h>
GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -148,14 +148,14 @@ bool GHOST_WindowSDL::getValid() const
return GHOST_Window::getValid() && m_valid_setup;
}
-void GHOST_WindowSDL::setTitle(const STR_String &title)
+void GHOST_WindowSDL::setTitle(const char *title)
{
- SDL_SetWindowTitle(m_sdl_win, title.ReadPtr());
+ SDL_SetWindowTitle(m_sdl_win, title);
}
-void GHOST_WindowSDL::getTitle(STR_String &title) const
+std::string GHOST_WindowSDL::getTitle() const
{
- title = SDL_GetWindowTitle(m_sdl_win);
+ return SDL_GetWindowTitle(m_sdl_win);
}
void GHOST_WindowSDL::getWindowBounds(GHOST_Rect &bounds) const
diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h
index eadd1b7df9d..5039c742c9d 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.h
+++ b/intern/ghost/intern/GHOST_WindowSDL.h
@@ -35,7 +35,6 @@ extern "C" {
# error "SDL 2.0 or newer is needed to build with Ghost"
#endif
-class STR_String;
class GHOST_SystemSDL;
class GHOST_WindowSDL : public GHOST_Window {
@@ -49,7 +48,7 @@ class GHOST_WindowSDL : public GHOST_Window {
public:
GHOST_WindowSDL(GHOST_SystemSDL *system,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -107,9 +106,9 @@ class GHOST_WindowSDL : public GHOST_Window {
GHOST_TSuccess setWindowCursorVisibility(bool visible);
- void setTitle(const STR_String &title);
+ void setTitle(const char *title);
- void getTitle(STR_String &title) const;
+ std::string getTitle() const;
GHOST_TSuccess setClientWidth(GHOST_TUns32 width);
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
new file mode 100644
index 00000000000..0ea6f5f8ecb
--- /dev/null
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -0,0 +1,406 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ */
+
+#include "GHOST_WindowWayland.h"
+#include "GHOST_SystemWayland.h"
+#include "GHOST_WindowManager.h"
+
+#include "GHOST_Event.h"
+
+#include "GHOST_ContextEGL.h"
+#include "GHOST_ContextNone.h"
+
+#include <wayland-egl.h>
+
+struct window_t {
+ GHOST_WindowWayland *w;
+ wl_surface *surface;
+ struct xdg_surface *xdg_surface;
+ struct xdg_toplevel *xdg_toplevel;
+ wl_egl_window *egl_window;
+ int32_t pending_width, pending_height;
+ bool is_maximised;
+ bool is_fullscreen;
+ bool is_active;
+ int32_t width, height;
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Wayland Interface Callbacks
+ *
+ * These callbacks are registered for Wayland interfaces and called when
+ * an event is received from the compositor.
+ * \{ */
+
+static void toplevel_configure(
+ void *data, xdg_toplevel * /*xdg_toplevel*/, int32_t width, int32_t height, wl_array *states)
+{
+ window_t *win = static_cast<window_t *>(data);
+ win->pending_width = width;
+ win->pending_height = height;
+
+ win->is_maximised = false;
+ win->is_fullscreen = false;
+ win->is_active = false;
+
+ /* Note that the macro 'wl_array_for_each' would typically be used to simplify this logic,
+ * however it's not compatible with C++, so perform casts instead.
+ * If this needs to be done more often we could define our own C++ compatible macro. */
+ for (enum xdg_toplevel_state *state = static_cast<xdg_toplevel_state *>(states->data);
+ reinterpret_cast<uint8_t *>(state) < (static_cast<uint8_t *>(states->data) + states->size);
+ state++) {
+ switch (*state) {
+ case XDG_TOPLEVEL_STATE_MAXIMIZED:
+ win->is_maximised = true;
+ break;
+ case XDG_TOPLEVEL_STATE_FULLSCREEN:
+ win->is_fullscreen = true;
+ break;
+ case XDG_TOPLEVEL_STATE_ACTIVATED:
+ win->is_active = true;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void toplevel_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
+{
+ static_cast<window_t *>(data)->w->close();
+}
+
+static const xdg_toplevel_listener toplevel_listener = {
+ toplevel_configure,
+ toplevel_close,
+};
+
+static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial)
+{
+ window_t *win = static_cast<window_t *>(data);
+
+ int w, h;
+ wl_egl_window_get_attached_size(win->egl_window, &w, &h);
+ if (win->pending_width != 0 && win->pending_height != 0 && win->pending_width != w &&
+ win->pending_height != h) {
+ win->width = win->pending_width;
+ win->height = win->pending_height;
+ wl_egl_window_resize(win->egl_window, win->pending_width, win->pending_height, 0, 0);
+ win->pending_width = 0;
+ win->pending_height = 0;
+ win->w->notify_size();
+ }
+
+ if (win->is_active) {
+ win->w->activate();
+ }
+ else {
+ win->w->deactivate();
+ }
+
+ xdg_surface_ack_configure(xdg_surface, serial);
+}
+
+static const xdg_surface_listener surface_listener = {
+ surface_configure,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Ghost Implementation
+ *
+ * Wayland specific implementation of the GHOST_Window interface.
+ * \{ */
+
+GHOST_TSuccess GHOST_WindowWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
+{
+ return m_system->hasCursorShape(cursorShape);
+}
+
+GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
+ const char *title,
+ GHOST_TInt32 /*left*/,
+ GHOST_TInt32 /*top*/,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ const GHOST_IWindow *parentWindow,
+ GHOST_TDrawingContextType type,
+ const bool stereoVisual,
+ const bool exclusive)
+ : GHOST_Window(width, height, state, stereoVisual, exclusive),
+ m_system(system),
+ w(new window_t)
+{
+ w->w = this;
+
+ w->width = int32_t(width);
+ w->height = int32_t(height);
+
+ /* Window surfaces. */
+ w->surface = wl_compositor_create_surface(m_system->compositor());
+ w->egl_window = wl_egl_window_create(w->surface, int(width), int(height));
+
+ w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->shell(), w->surface);
+ w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
+
+ wl_surface_set_user_data(w->surface, this);
+
+ xdg_surface_add_listener(w->xdg_surface, &surface_listener, w);
+ xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
+
+ if (parentWindow) {
+ xdg_toplevel_set_parent(
+ w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel);
+ }
+
+ /* Call top-level callbacks. */
+ wl_surface_commit(w->surface);
+ wl_display_roundtrip(m_system->display());
+
+ setState(state);
+
+ setTitle(title);
+
+ /* EGL context. */
+ if (setDrawingContextType(type) == GHOST_kFailure) {
+ GHOST_PRINT("Failed to create EGL context" << std::endl);
+ }
+}
+
+GHOST_TSuccess GHOST_WindowWayland::close()
+{
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowClose, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::activate()
+{
+ if (m_system->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
+ return GHOST_kFailure;
+ }
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowActivate, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::deactivate()
+{
+ m_system->getWindowManager()->setWindowInactive(this);
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowDeactivate, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::notify_size()
+{
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
+{
+ return m_system->setCursorGrab(mode, w->surface);
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape)
+{
+ const GHOST_TSuccess ok = m_system->setCursorShape(shape);
+ m_cursorShape = (ok == GHOST_kSuccess) ? shape : GHOST_kStandardCursorDefault;
+ return ok;
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
+ GHOST_TUns8 *mask,
+ int sizex,
+ int sizey,
+ int hotX,
+ int hotY,
+ bool canInvertColor)
+{
+ return m_system->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
+}
+
+void GHOST_WindowWayland::setTitle(const char *title)
+{
+ xdg_toplevel_set_title(w->xdg_toplevel, title);
+ xdg_toplevel_set_app_id(w->xdg_toplevel, title);
+ this->title = title;
+}
+
+std::string GHOST_WindowWayland::getTitle() const
+{
+ return this->title.empty() ? "untitled" : this->title;
+}
+
+void GHOST_WindowWayland::getWindowBounds(GHOST_Rect &bounds) const
+{
+ getClientBounds(bounds);
+}
+
+void GHOST_WindowWayland::getClientBounds(GHOST_Rect &bounds) const
+{
+ bounds.set(0, 0, w->width, w->height);
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setClientWidth(GHOST_TUns32 width)
+{
+ return setClientSize(width, GHOST_TUns32(w->height));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setClientHeight(GHOST_TUns32 height)
+{
+ return setClientSize(GHOST_TUns32(w->width), height);
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
+{
+ wl_egl_window_resize(w->egl_window, int(width), int(height), 0, 0);
+ return GHOST_kSuccess;
+}
+
+void GHOST_WindowWayland::screenToClient(GHOST_TInt32 inX,
+ GHOST_TInt32 inY,
+ GHOST_TInt32 &outX,
+ GHOST_TInt32 &outY) const
+{
+ outX = inX;
+ outY = inY;
+}
+
+void GHOST_WindowWayland::clientToScreen(GHOST_TInt32 inX,
+ GHOST_TInt32 inY,
+ GHOST_TInt32 &outX,
+ GHOST_TInt32 &outY) const
+{
+ outX = inX;
+ outY = inY;
+}
+
+GHOST_WindowWayland::~GHOST_WindowWayland()
+{
+ releaseNativeHandles();
+
+ wl_egl_window_destroy(w->egl_window);
+ xdg_toplevel_destroy(w->xdg_toplevel);
+ xdg_surface_destroy(w->xdg_surface);
+ wl_surface_destroy(w->surface);
+
+ delete w;
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible)
+{
+ return m_system->setCursorVisibility(visible);
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state)
+{
+ switch (state) {
+ case GHOST_kWindowStateNormal:
+ /* Unset states. */
+ switch (getState()) {
+ case GHOST_kWindowStateMaximized:
+ xdg_toplevel_unset_maximized(w->xdg_toplevel);
+ break;
+ case GHOST_kWindowStateFullScreen:
+ xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+ break;
+ default:
+ break;
+ }
+ break;
+ case GHOST_kWindowStateMaximized:
+ xdg_toplevel_set_maximized(w->xdg_toplevel);
+ break;
+ case GHOST_kWindowStateMinimized:
+ xdg_toplevel_set_minimized(w->xdg_toplevel);
+ break;
+ case GHOST_kWindowStateFullScreen:
+ xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
+ break;
+ case GHOST_kWindowStateEmbedded:
+ return GHOST_kFailure;
+ }
+ return GHOST_kSuccess;
+}
+
+GHOST_TWindowState GHOST_WindowWayland::getState() const
+{
+ if (w->is_fullscreen) {
+ return GHOST_kWindowStateFullScreen;
+ }
+ else if (w->is_maximised) {
+ return GHOST_kWindowStateMaximized;
+ }
+ else {
+ return GHOST_kWindowStateNormal;
+ }
+}
+
+GHOST_TSuccess GHOST_WindowWayland::invalidate()
+{
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setOrder(GHOST_TWindowOrder /*order*/)
+{
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_WindowWayland::beginFullScreen() const
+{
+ xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_WindowWayland::endFullScreen() const
+{
+ xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+ return GHOST_kSuccess;
+}
+
+/**
+ * \param type The type of rendering context create.
+ * \return Indication of success.
+ */
+GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType type)
+{
+ GHOST_Context *context;
+ switch (type) {
+ case GHOST_kDrawingContextTypeNone:
+ context = new GHOST_ContextNone(m_wantStereoVisual);
+ break;
+ case GHOST_kDrawingContextTypeOpenGL:
+ context = new GHOST_ContextEGL(m_wantStereoVisual,
+ EGLNativeWindowType(w->egl_window),
+ EGLNativeDisplayType(m_system->display()),
+ EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
+ 3,
+ 3,
+ GHOST_OPENGL_EGL_CONTEXT_FLAGS,
+ GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
+ EGL_OPENGL_API);
+ break;
+ }
+
+ return (context->initializeDrawingContext() == GHOST_kSuccess) ? context : nullptr;
+}
+
+/** \} */
diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h
new file mode 100644
index 00000000000..39c35f77d7d
--- /dev/null
+++ b/intern/ghost/intern/GHOST_WindowWayland.h
@@ -0,0 +1,121 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ *
+ * Declaration of GHOST_WindowWayland class.
+ */
+
+#ifndef __GHOST_WINDOWWAYLAND_H__
+#define __GHOST_WINDOWWAYLAND_H__
+
+#include "GHOST_Window.h"
+
+class GHOST_SystemWayland;
+
+struct window_t;
+
+class GHOST_WindowWayland : public GHOST_Window {
+ public:
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape) override;
+
+ GHOST_WindowWayland(GHOST_SystemWayland *system,
+ const char *title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ const GHOST_IWindow *parentWindow,
+ GHOST_TDrawingContextType type,
+ const bool stereoVisual,
+ const bool exclusive);
+
+ ~GHOST_WindowWayland() override;
+
+ GHOST_TSuccess close();
+
+ GHOST_TSuccess activate();
+
+ GHOST_TSuccess deactivate();
+
+ GHOST_TSuccess notify_size();
+
+ protected:
+ GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override;
+
+ GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override;
+
+ GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
+ GHOST_TUns8 *mask,
+ int sizex,
+ int sizey,
+ int hotX,
+ int hotY,
+ bool canInvertColor) override;
+
+ void setTitle(const char *title) override;
+
+ std::string getTitle() const override;
+
+ void getWindowBounds(GHOST_Rect &bounds) const override;
+
+ void getClientBounds(GHOST_Rect &bounds) const override;
+
+ GHOST_TSuccess setClientWidth(GHOST_TUns32 width) override;
+
+ GHOST_TSuccess setClientHeight(GHOST_TUns32 height) override;
+
+ GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) override;
+
+ void screenToClient(GHOST_TInt32 inX,
+ GHOST_TInt32 inY,
+ GHOST_TInt32 &outX,
+ GHOST_TInt32 &outY) const override;
+
+ void clientToScreen(GHOST_TInt32 inX,
+ GHOST_TInt32 inY,
+ GHOST_TInt32 &outX,
+ GHOST_TInt32 &outY) const override;
+
+ GHOST_TSuccess setWindowCursorVisibility(bool visible) override;
+
+ GHOST_TSuccess setState(GHOST_TWindowState state) override;
+
+ GHOST_TWindowState getState() const override;
+
+ GHOST_TSuccess invalidate() override;
+
+ GHOST_TSuccess setOrder(GHOST_TWindowOrder order) override;
+
+ GHOST_TSuccess beginFullScreen() const override;
+
+ GHOST_TSuccess endFullScreen() const override;
+
+ private:
+ GHOST_SystemWayland *m_system;
+ struct window_t *w;
+ std::string title;
+
+ /**
+ * \param type The type of rendering context create.
+ * \return Indication of success.
+ */
+ GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type) override;
+};
+
+#endif // __GHOST_WINDOWWAYLAND_H__
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 8b95cdd6351..55525157753 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -59,7 +59,7 @@ __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
}
GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -158,7 +158,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
height = rect.bottom - rect.top;
}
- wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
+ wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
m_hWnd = ::CreateWindowW(s_windowClassName, // pointer to registered class name
title_16, // pointer to window name
wintype, // window style
@@ -173,7 +173,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
free(title_16);
}
else {
- wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
+ wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
m_hWnd = ::CreateWindowW(s_windowClassName, // pointer to registered class name
title_16, // pointer to window name
WS_MAXIMIZE, // window style
@@ -430,19 +430,18 @@ HWND GHOST_WindowWin32::getHWND() const
return m_hWnd;
}
-void GHOST_WindowWin32::setTitle(const STR_String &title)
+void GHOST_WindowWin32::setTitle(const char *title)
{
- wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
+ wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
::SetWindowTextW(m_hWnd, (wchar_t *)title_16);
free(title_16);
}
-void GHOST_WindowWin32::getTitle(STR_String &title) const
+std::string GHOST_WindowWin32::getTitle() const
{
char buf[s_maxTitleLength]; /*CHANGE + never used yet*/
::GetWindowText(m_hWnd, buf, s_maxTitleLength);
- STR_String temp(buf);
- title = buf;
+ return std::string(buf);
}
void GHOST_WindowWin32::getWindowBounds(GHOST_Rect &bounds) const
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index 489d3032552..dbed7c5ee5f 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -261,7 +261,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
* \param parentWindowHwnd
*/
GHOST_WindowWin32(GHOST_SystemWin32 *system,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -296,13 +296,13 @@ class GHOST_WindowWin32 : public GHOST_Window {
* Sets the title displayed in the title bar.
* \param title The title to display in the title bar.
*/
- void setTitle(const STR_String &title);
+ void setTitle(const char *title);
/**
* Returns the title displayed in the title bar.
- * \param title The title displayed in the title bar.
+ * \return The title displayed in the title bar.
*/
- void getTitle(STR_String &title) const;
+ std::string getTitle() const;
/**
* Returns the window rectangle dimensions.
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index db9f6846b11..691f1790a2d 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -33,7 +33,6 @@
#include "GHOST_IconX11.h"
#include "GHOST_SystemX11.h"
#include "GHOST_WindowX11.h"
-#include "STR_String.h"
#ifdef WITH_XDND
# include "GHOST_DropTargetX11.h"
@@ -61,6 +60,7 @@
#include <unistd.h>
#include <algorithm>
+#include <limits.h>
#include <math.h>
#include <string>
@@ -212,7 +212,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
Display *display,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -414,9 +414,9 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
/* XClassHint, title */
{
XClassHint *xclasshint = XAllocClassHint();
- const int len = title.Length() + 1;
+ const int len = strlen(title) + 1;
char *wmclass = (char *)malloc(sizeof(char) * len);
- memcpy(wmclass, title.ReadPtr(), len * sizeof(char));
+ memcpy(wmclass, title, len * sizeof(char));
xclasshint->res_name = wmclass;
xclasshint->res_class = wmclass;
XSetClassHint(m_display, m_window, xclasshint);
@@ -617,7 +617,7 @@ bool GHOST_WindowX11::getValid() const
return GHOST_Window::getValid() && m_valid_setup;
}
-void GHOST_WindowX11::setTitle(const STR_String &title)
+void GHOST_WindowX11::setTitle(const char *title)
{
Atom name = XInternAtom(m_display, "_NET_WM_NAME", 0);
Atom utf8str = XInternAtom(m_display, "UTF8_STRING", 0);
@@ -627,8 +627,8 @@ void GHOST_WindowX11::setTitle(const STR_String &title)
utf8str,
8,
PropModeReplace,
- (const unsigned char *)title.ReadPtr(),
- title.Length());
+ (const unsigned char *)title,
+ strlen(title));
/* This should convert to valid x11 string
* and getTitle would need matching change */
@@ -637,13 +637,14 @@ void GHOST_WindowX11::setTitle(const STR_String &title)
XFlush(m_display);
}
-void GHOST_WindowX11::getTitle(STR_String &title) const
+std::string GHOST_WindowX11::getTitle() const
{
char *name = NULL;
XFetchName(m_display, m_window, &name);
- title = name ? name : "untitled";
+ std::string title = name ? name : "untitled";
XFree(name);
+ return title;
}
void GHOST_WindowX11::getWindowBounds(GHOST_Rect &bounds) const
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index 4704cb45e58..4232ff40b52 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -37,7 +37,6 @@
#include <map>
-class STR_String;
class GHOST_SystemX11;
#ifdef WITH_XDND
@@ -69,7 +68,7 @@ class GHOST_WindowX11 : public GHOST_Window {
*/
GHOST_WindowX11(GHOST_SystemX11 *system,
Display *display,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -85,9 +84,9 @@ class GHOST_WindowX11 : public GHOST_Window {
bool getValid() const;
- void setTitle(const STR_String &title);
+ void setTitle(const char *title);
- void getTitle(STR_String &title) const;
+ std::string getTitle() const;
void getWindowBounds(GHOST_Rect &bounds) const;
diff --git a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
index 60b3b06f6a8..5e30502f7ff 100644
--- a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
+++ b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
@@ -22,7 +22,7 @@
#include <list>
#include <sstream>
-#if defined(WITH_X11)
+#if defined(WITH_GHOST_X11)
# include "GHOST_ContextGLX.h"
#elif defined(WIN32)
# include "GHOST_ContextD3D.h"
@@ -68,7 +68,7 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
XrSystemId system_id,
std::string *r_requirement_info) const override
{
-#if defined(WITH_X11)
+#if defined(WITH_GHOST_X11)
GHOST_ContextGLX *ctx_gl = static_cast<GHOST_ContextGLX *>(ghost_ctx);
#else
GHOST_ContextWGL *ctx_gl = static_cast<GHOST_ContextWGL *>(ghost_ctx);
@@ -107,7 +107,7 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
void initFromGhostContext(GHOST_Context *ghost_ctx) override
{
-#if defined(WITH_X11)
+#if defined(WITH_GHOST_X11)
GHOST_ContextGLX *ctx_glx = static_cast<GHOST_ContextGLX *>(ghost_ctx);
XVisualInfo *visual_info = glXGetVisualFromFBConfig(ctx_glx->m_display, ctx_glx->m_fbconfig);
diff --git a/intern/ghost/intern/GHOST_Xr_openxr_includes.h b/intern/ghost/intern/GHOST_Xr_openxr_includes.h
index 925d6037750..9cac43b1549 100644
--- a/intern/ghost/intern/GHOST_Xr_openxr_includes.h
+++ b/intern/ghost/intern/GHOST_Xr_openxr_includes.h
@@ -42,7 +42,7 @@
#ifdef XR_USE_GRAPHICS_API_D3D12
# include <d3d12.h>
#endif
-#ifdef WITH_X11
+#ifdef WITH_GHOST_X11
# include <GL/glxew.h>
#endif
diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt
index eda41eb9c1a..b6e3c0ecf5f 100644
--- a/intern/ghost/test/CMakeLists.txt
+++ b/intern/ghost/test/CMakeLists.txt
@@ -85,8 +85,9 @@ endif()
# Libraries
if(UNIX AND NOT APPLE)
- set(WITH_X11 ON)
+ set(WITH_GHOST_X11 ON)
endif()
+
# for now... default to this
add_definitions(-DWITH_GL_PROFILE_COMPAT)
# BLF needs this to ignore GPU library
diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp
index a554bfeebef..c9c497aacb4 100644
--- a/intern/ghost/test/gears/GHOST_Test.cpp
+++ b/intern/ghost/test/gears/GHOST_Test.cpp
@@ -27,6 +27,7 @@
#include <iostream>
#include <math.h>
+#include <string>
#if defined(WIN32) || defined(__APPLE__)
# ifdef WIN32
@@ -43,7 +44,6 @@
#endif // defined(WIN32) || defined(__APPLE__)
#include "GHOST_Rect.h"
-#include "STR_String.h"
#include "GHOST_IEvent.h"
#include "GHOST_IEventConsumer.h"
@@ -427,8 +427,7 @@ Application::Application(GHOST_ISystem *system)
fApp = this;
// Create the main window
- STR_String title1("gears - main window");
- m_mainWindow = system->createWindow(title1,
+ m_mainWindow = system->createWindow("gears - main window",
10,
64,
320,
@@ -443,8 +442,7 @@ Application::Application(GHOST_ISystem *system)
}
// Create a secondary window
- STR_String title2("gears - secondary window");
- m_secondaryWindow = system->createWindow(title2,
+ m_secondaryWindow = system->createWindow("gears - secondary window",
340,
64,
320,
@@ -598,8 +596,7 @@ bool Application::processEvent(GHOST_IEvent *event)
case GHOST_kKeyW:
if (m_mainWindow) {
- STR_String title;
- m_mainWindow->getTitle(title);
+ std::string title = m_mainWindow->getTitle();
title += "-";
m_mainWindow->setTitle(title);
}
diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc
index 89e3d0d1178..554c4350b0a 100644
--- a/intern/libmv/intern/camera_intrinsics.cc
+++ b/intern/libmv/intern/camera_intrinsics.cc
@@ -24,6 +24,7 @@
using libmv::CameraIntrinsics;
using libmv::DivisionCameraIntrinsics;
using libmv::PolynomialCameraIntrinsics;
+using libmv::NukeCameraIntrinsics;
libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) {
@@ -55,6 +56,14 @@ libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
*division_intrinsics);
break;
}
+ case libmv::DISTORTION_MODEL_NUKE:
+ {
+ const NukeCameraIntrinsics *nuke_intrinsics =
+ static_cast<const NukeCameraIntrinsics*>(orig_intrinsics);
+ new_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics,
+ *nuke_intrinsics);
+ break;
+ }
default:
assert(!"Unknown distortion model");
}
@@ -136,6 +145,25 @@ void libmv_cameraIntrinsicsUpdate(
break;
}
+ case LIBMV_DISTORTION_MODEL_NUKE:
+ {
+ assert(camera_intrinsics->GetDistortionModelType() ==
+ libmv::DISTORTION_MODEL_NUKE);
+
+ NukeCameraIntrinsics *nuke_intrinsics =
+ (NukeCameraIntrinsics *) camera_intrinsics;
+
+ double k1 = libmv_camera_intrinsics_options->nuke_k1;
+ double k2 = libmv_camera_intrinsics_options->nuke_k2;
+
+ if (nuke_intrinsics->k1() != k1 ||
+ nuke_intrinsics->k2() != k2) {
+ nuke_intrinsics->SetDistortion(k1, k2);
+ }
+
+ break;
+ }
+
default:
assert(!"Unknown distortion model");
}
@@ -189,6 +217,17 @@ void libmv_cameraIntrinsicsExtractOptions(
break;
}
+ case libmv::DISTORTION_MODEL_NUKE:
+ {
+ const NukeCameraIntrinsics *nuke_intrinsics =
+ static_cast<const NukeCameraIntrinsics *>(camera_intrinsics);
+ camera_intrinsics_options->distortion_model =
+ LIBMV_DISTORTION_MODEL_NUKE;
+ camera_intrinsics_options->nuke_k1 = nuke_intrinsics->k1();
+ camera_intrinsics_options->nuke_k2 = nuke_intrinsics->k2();
+ break;
+ }
+
default:
assert(!"Unknown distortion model");
}
@@ -316,6 +355,17 @@ static void libmv_cameraIntrinsicsFillFromOptions(
break;
}
+ case LIBMV_DISTORTION_MODEL_NUKE:
+ {
+ NukeCameraIntrinsics *nuke_intrinsics =
+ static_cast<NukeCameraIntrinsics*>(camera_intrinsics);
+
+ nuke_intrinsics->SetDistortion(
+ camera_intrinsics_options->nuke_k1,
+ camera_intrinsics_options->nuke_k2);
+ break;
+ }
+
default:
assert(!"Unknown distortion model");
}
@@ -331,6 +381,9 @@ CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions(
case LIBMV_DISTORTION_MODEL_DIVISION:
camera_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics);
break;
+ case LIBMV_DISTORTION_MODEL_NUKE:
+ camera_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics);
+ break;
default:
assert(!"Unknown distortion model");
}
diff --git a/intern/libmv/intern/camera_intrinsics.h b/intern/libmv/intern/camera_intrinsics.h
index 40a5826a9c4..b3d259893bd 100644
--- a/intern/libmv/intern/camera_intrinsics.h
+++ b/intern/libmv/intern/camera_intrinsics.h
@@ -29,6 +29,7 @@ typedef struct libmv_CameraIntrinsics libmv_CameraIntrinsics;
enum {
LIBMV_DISTORTION_MODEL_POLYNOMIAL = 0,
LIBMV_DISTORTION_MODEL_DIVISION = 1,
+ LIBMV_DISTORTION_MODEL_NUKE = 2,
};
typedef struct libmv_CameraIntrinsicsOptions {
@@ -45,6 +46,9 @@ typedef struct libmv_CameraIntrinsicsOptions {
// Division distortion model.
double division_k1, division_k2;
+
+ // Nuke distortion model.
+ double nuke_k1, nuke_k2;
} libmv_CameraIntrinsicsOptions;
libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
diff --git a/intern/libmv/libmv/simple_pipeline/bundle.cc b/intern/libmv/libmv/simple_pipeline/bundle.cc
index e61650fb371..a70fdbc9888 100644
--- a/intern/libmv/libmv/simple_pipeline/bundle.cc
+++ b/intern/libmv/libmv/simple_pipeline/bundle.cc
@@ -66,18 +66,221 @@ enum {
namespace {
-// Cost functor which computes reprojection error of 3D point X
-// on camera defined by angle-axis rotation and it's translation
-// (which are in the same block due to optimization reasons).
+bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics *intrinsics) {
+ const DistortionModelType distortion_model =
+ intrinsics->GetDistortionModelType();
+ return (distortion_model == DISTORTION_MODEL_NUKE);
+}
+
+// Apply distortion model (distort the input) on the input point in the
+// normalized space to get distorted coordinate in the image space.
+//
+// Using intrinsics values from the parameter block, which makes this function
+// suitable for use from a cost functor.
+//
+// Only use for distortion models which are analytically defined for their
+// Apply() function.
+//
+// The invariant_intrinsics are used to access intrinsics which are never
+// packed into parameter block: for example, distortion model type and image
+// dimension.
+template<typename T>
+void ApplyDistortionModelUsingIntrinsicsBlock(
+ const CameraIntrinsics *invariant_intrinsics,
+ const T* const intrinsics_block,
+ const T& normalized_x, const T& normalized_y,
+ T* distorted_x, T* distorted_y) {
+ // Unpack the intrinsics.
+ const T& focal_length = intrinsics_block[OFFSET_FOCAL_LENGTH];
+ const T& principal_point_x = intrinsics_block[OFFSET_PRINCIPAL_POINT_X];
+ const T& principal_point_y = intrinsics_block[OFFSET_PRINCIPAL_POINT_Y];
+
+ // TODO(keir): Do early bailouts for zero distortion; these are expensive
+ // jet operations.
+ switch (invariant_intrinsics->GetDistortionModelType()) {
+ case DISTORTION_MODEL_POLYNOMIAL:
+ {
+ const T& k1 = intrinsics_block[OFFSET_K1];
+ const T& k2 = intrinsics_block[OFFSET_K2];
+ const T& k3 = intrinsics_block[OFFSET_K3];
+ const T& p1 = intrinsics_block[OFFSET_P1];
+ const T& p2 = intrinsics_block[OFFSET_P2];
+
+ ApplyPolynomialDistortionModel(focal_length,
+ focal_length,
+ principal_point_x,
+ principal_point_y,
+ k1, k2, k3,
+ p1, p2,
+ normalized_x, normalized_y,
+ distorted_x, distorted_y);
+ return;
+ }
+
+ case DISTORTION_MODEL_DIVISION:
+ {
+ const T& k1 = intrinsics_block[OFFSET_K1];
+ const T& k2 = intrinsics_block[OFFSET_K2];
+
+ ApplyDivisionDistortionModel(focal_length,
+ focal_length,
+ principal_point_x,
+ principal_point_y,
+ k1, k2,
+ normalized_x, normalized_y,
+ distorted_x, distorted_y);
+ return;
+ }
+
+ case DISTORTION_MODEL_NUKE:
+ {
+ LOG(FATAL) << "Unsupported distortion model.";
+ return;
+ }
+ }
+
+ LOG(FATAL) << "Unknown distortion model.";
+}
+
+// Invert distortion model (undistort the input) on the input point in the
+// image space to get undistorted coordinate in the normalized space.
+//
+// Using intrinsics values from the parameter block, which makes this function
+// suitable for use from a cost functor.
+//
+// Only use for distortion models which are analytically defined for their
+// Invert() function.
+//
+// The invariant_intrinsics are used to access intrinsics which are never
+// packed into parameter block: for example, distortion model type and image
+// dimension.
+template<typename T>
+void InvertDistortionModelUsingIntrinsicsBlock(
+ const CameraIntrinsics *invariant_intrinsics,
+ const T* const intrinsics_block,
+ const T& image_x, const T& image_y,
+ T* normalized_x, T* normalized_y) {
+ // Unpack the intrinsics.
+ const T& focal_length = intrinsics_block[OFFSET_FOCAL_LENGTH];
+ const T& principal_point_x = intrinsics_block[OFFSET_PRINCIPAL_POINT_X];
+ const T& principal_point_y = intrinsics_block[OFFSET_PRINCIPAL_POINT_Y];
+
+ // TODO(keir): Do early bailouts for zero distortion; these are expensive
+ // jet operations.
+ switch (invariant_intrinsics->GetDistortionModelType()) {
+ case DISTORTION_MODEL_POLYNOMIAL:
+ case DISTORTION_MODEL_DIVISION:
+ LOG(FATAL) << "Unsupported distortion model.";
+ return;
+
+ case DISTORTION_MODEL_NUKE:
+ {
+ const T& k1 = intrinsics_block[OFFSET_K1];
+ const T& k2 = intrinsics_block[OFFSET_K2];
+
+ InvertNukeDistortionModel(focal_length,
+ focal_length,
+ principal_point_x,
+ principal_point_y,
+ invariant_intrinsics->image_width(),
+ invariant_intrinsics->image_height(),
+ k1, k2,
+ image_x, image_y,
+ normalized_x, normalized_y);
+ return;
+ }
+ }
+
+ LOG(FATAL) << "Unknown distortion model.";
+}
+
+template<typename T>
+void NormalizedToImageSpace(const T* const intrinsics_block,
+ const T& normalized_x, const T& normalized_y,
+ T* image_x, T* image_y) {
+ // Unpack the intrinsics.
+ const T& focal_length = intrinsics_block[OFFSET_FOCAL_LENGTH];
+ const T& principal_point_x = intrinsics_block[OFFSET_PRINCIPAL_POINT_X];
+ const T& principal_point_y = intrinsics_block[OFFSET_PRINCIPAL_POINT_Y];
+
+ *image_x = normalized_x * focal_length + principal_point_x;
+ *image_y = normalized_y * focal_length + principal_point_y;
+}
+
+// Cost functor which computes reprojection error of 3D point X on camera
+// defined by angle-axis rotation and it's translation (which are in the same
+// block due to optimization reasons).
+//
+// This functor can only be used for distortion models which have analytically
+// defined Apply() function.
+struct ReprojectionErrorApplyIntrinsics {
+ ReprojectionErrorApplyIntrinsics(
+ const CameraIntrinsics *invariant_intrinsics,
+ const double observed_distorted_x,
+ const double observed_distorted_y,
+ const double weight)
+ : invariant_intrinsics_(invariant_intrinsics),
+ observed_distorted_x_(observed_distorted_x),
+ observed_distorted_y_(observed_distorted_y),
+ weight_(weight) {}
+
+ template <typename T>
+ bool operator()(const T* const intrinsics,
+ const T* const R_t, // Rotation denoted by angle axis
+ // followed with translation
+ const T* const X, // Point coordinates 3x1.
+ T* residuals) const {
+ // Compute projective coordinates: x = RX + t.
+ T x[3];
+
+ ceres::AngleAxisRotatePoint(R_t, X, x);
+ x[0] += R_t[3];
+ x[1] += R_t[4];
+ x[2] += R_t[5];
+
+ // Prevent points from going behind the camera.
+ if (x[2] < T(0)) {
+ return false;
+ }
+
+ // Compute normalized coordinates: x /= x[2].
+ T xn = x[0] / x[2];
+ T yn = x[1] / x[2];
+
+ T predicted_distorted_x, predicted_distorted_y;
+ ApplyDistortionModelUsingIntrinsicsBlock(
+ invariant_intrinsics_,
+ intrinsics,
+ xn, yn,
+ &predicted_distorted_x, &predicted_distorted_y);
+
+ // The error is the difference between the predicted and observed position.
+ residuals[0] = (predicted_distorted_x - T(observed_distorted_x_)) * weight_;
+ residuals[1] = (predicted_distorted_y - T(observed_distorted_y_)) * weight_;
+ return true;
+ }
+
+ const CameraIntrinsics *invariant_intrinsics_;
+ const double observed_distorted_x_;
+ const double observed_distorted_y_;
+ const double weight_;
+};
+
+// Cost functor which computes reprojection error of 3D point X on camera
+// defined by angle-axis rotation and it's translation (which are in the same
+// block due to optimization reasons).
//
-// This functor uses a radial distortion model.
-struct OpenCVReprojectionError {
- OpenCVReprojectionError(const DistortionModelType distortion_model,
- const double observed_x,
- const double observed_y,
- const double weight)
- : distortion_model_(distortion_model),
- observed_x_(observed_x), observed_y_(observed_y),
+// This functor can only be used for distortion models which have analytically
+// defined Invert() function.
+struct ReprojectionErrorInvertIntrinsics {
+ ReprojectionErrorInvertIntrinsics(
+ const CameraIntrinsics *invariant_intrinsics,
+ const double observed_distorted_x,
+ const double observed_distorted_y,
+ const double weight)
+ : invariant_intrinsics_(invariant_intrinsics),
+ observed_distorted_x_(observed_distorted_x),
+ observed_distorted_y_(observed_distorted_y),
weight_(weight) {}
template <typename T>
@@ -108,63 +311,37 @@ struct OpenCVReprojectionError {
T xn = x[0] / x[2];
T yn = x[1] / x[2];
- T predicted_x, predicted_y;
-
- // Apply distortion to the normalized points to get (xd, yd).
- // TODO(keir): Do early bailouts for zero distortion; these are expensive
- // jet operations.
- switch (distortion_model_) {
- case DISTORTION_MODEL_POLYNOMIAL:
- {
- const T& k1 = intrinsics[OFFSET_K1];
- const T& k2 = intrinsics[OFFSET_K2];
- const T& k3 = intrinsics[OFFSET_K3];
- const T& p1 = intrinsics[OFFSET_P1];
- const T& p2 = intrinsics[OFFSET_P2];
-
- ApplyPolynomialDistortionModel(focal_length,
- focal_length,
- principal_point_x,
- principal_point_y,
- k1, k2, k3,
- p1, p2,
- xn, yn,
- &predicted_x,
- &predicted_y);
- break;
- }
- case DISTORTION_MODEL_DIVISION:
- {
- const T& k1 = intrinsics[OFFSET_K1];
- const T& k2 = intrinsics[OFFSET_K2];
+ // Compute image space coordinate from normalized.
+ T predicted_x = focal_length * xn + principal_point_x;
+ T predicted_y = focal_length * yn + principal_point_y;
- ApplyDivisionDistortionModel(focal_length,
- focal_length,
- principal_point_x,
- principal_point_y,
- k1, k2,
- xn, yn,
- &predicted_x,
- &predicted_y);
- break;
- }
- default:
- LOG(FATAL) << "Unknown distortion model";
- }
+ T observed_undistorted_normalized_x, observed_undistorted_normalized_y;
+ InvertDistortionModelUsingIntrinsicsBlock(
+ invariant_intrinsics_,
+ intrinsics,
+ T(observed_distorted_x_), T(observed_distorted_y_),
+ &observed_undistorted_normalized_x, &observed_undistorted_normalized_y);
+
+ T observed_undistorted_image_x, observed_undistorted_image_y;
+ NormalizedToImageSpace(
+ intrinsics,
+ observed_undistorted_normalized_x, observed_undistorted_normalized_y,
+ &observed_undistorted_image_x, &observed_undistorted_image_y);
// The error is the difference between the predicted and observed position.
- residuals[0] = (predicted_x - T(observed_x_)) * weight_;
- residuals[1] = (predicted_y - T(observed_y_)) * weight_;
+ residuals[0] = (predicted_x - observed_undistorted_image_x) * weight_;
+ residuals[1] = (predicted_y - observed_undistorted_image_y) * weight_;
+
return true;
}
- const DistortionModelType distortion_model_;
- const double observed_x_;
- const double observed_y_;
+ const CameraIntrinsics *invariant_intrinsics_;
+ const double observed_distorted_x_;
+ const double observed_distorted_y_;
const double weight_;
};
-// Print a message to the log which camera intrinsics are gonna to be optimixed.
+// Print a message to the log which camera intrinsics are gonna to be optimized.
void BundleIntrinsicsLogMessage(const int bundle_intrinsics) {
if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
LOG(INFO) << "Bundling only camera positions.";
@@ -193,29 +370,29 @@ void BundleIntrinsicsLogMessage(const int bundle_intrinsics) {
// Pack intrinsics from object to an array for easier
// and faster minimization.
void PackIntrinisicsIntoArray(const CameraIntrinsics &intrinsics,
- double ceres_intrinsics[OFFSET_MAX]) {
- ceres_intrinsics[OFFSET_FOCAL_LENGTH] = intrinsics.focal_length();
- ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X] = intrinsics.principal_point_x();
- ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y] = intrinsics.principal_point_y();
+ double intrinsics_block[OFFSET_MAX]) {
+ intrinsics_block[OFFSET_FOCAL_LENGTH] = intrinsics.focal_length();
+ intrinsics_block[OFFSET_PRINCIPAL_POINT_X] = intrinsics.principal_point_x();
+ intrinsics_block[OFFSET_PRINCIPAL_POINT_Y] = intrinsics.principal_point_y();
int num_distortion_parameters = intrinsics.num_distortion_parameters();
assert(num_distortion_parameters <= NUM_DISTORTION_COEFFICIENTS);
const double *distortion_parameters = intrinsics.distortion_parameters();
for (int i = 0; i < num_distortion_parameters; ++i) {
- ceres_intrinsics[FIRST_DISTORTION_COEFFICIENT + i] =
+ intrinsics_block[FIRST_DISTORTION_COEFFICIENT + i] =
distortion_parameters[i];
}
}
// Unpack intrinsics back from an array to an object.
-void UnpackIntrinsicsFromArray(const double ceres_intrinsics[OFFSET_MAX],
+void UnpackIntrinsicsFromArray(const double intrinsics_block[OFFSET_MAX],
CameraIntrinsics *intrinsics) {
- intrinsics->SetFocalLength(ceres_intrinsics[OFFSET_FOCAL_LENGTH],
- ceres_intrinsics[OFFSET_FOCAL_LENGTH]);
+ intrinsics->SetFocalLength(intrinsics_block[OFFSET_FOCAL_LENGTH],
+ intrinsics_block[OFFSET_FOCAL_LENGTH]);
- intrinsics->SetPrincipalPoint(ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X],
- ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y]);
+ intrinsics->SetPrincipalPoint(intrinsics_block[OFFSET_PRINCIPAL_POINT_X],
+ intrinsics_block[OFFSET_PRINCIPAL_POINT_Y]);
int num_distortion_parameters = intrinsics->num_distortion_parameters();
assert(num_distortion_parameters <= NUM_DISTORTION_COEFFICIENTS);
@@ -223,7 +400,7 @@ void UnpackIntrinsicsFromArray(const double ceres_intrinsics[OFFSET_MAX],
double *distortion_parameters = intrinsics->distortion_parameters();
for (int i = 0; i < num_distortion_parameters; ++i) {
distortion_parameters[i] =
- ceres_intrinsics[FIRST_DISTORTION_COEFFICIENT + i];
+ intrinsics_block[FIRST_DISTORTION_COEFFICIENT + i];
}
}
@@ -302,68 +479,117 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks,
vector<Vec6> *all_cameras_R_t,
ceres::Problem *problem,
BundleEvaluation *evaluation) {
- int max_track = tracks.MaxTrack();
- // Number of camera rotations equals to number of translation,
- int num_cameras = all_cameras_R_t->size();
- int num_points = 0;
-
- vector<EuclideanPoint*> minimized_points;
- for (int i = 0; i <= max_track; i++) {
- EuclideanPoint *point = reconstruction->PointForTrack(i);
- if (point) {
- // We need to know whether the track is constant zero weight,
- // and it so it wouldn't have parameter block in the problem.
- //
- // Getting all markers for track is not so bac currently since
- // this code is only used by keyframe selection when there are
- // not so much tracks and only 2 frames anyway.
- vector<Marker> markera_of_track = tracks.MarkersForTrack(i);
- for (int j = 0; j < markera_of_track.size(); j++) {
- if (markera_of_track.at(j).weight != 0.0) {
- minimized_points.push_back(point);
- num_points++;
- break;
- }
+ int max_track = tracks.MaxTrack();
+ // Number of camera rotations equals to number of translation,
+ int num_cameras = all_cameras_R_t->size();
+ int num_points = 0;
+
+ vector<EuclideanPoint*> minimized_points;
+ for (int i = 0; i <= max_track; i++) {
+ EuclideanPoint *point = reconstruction->PointForTrack(i);
+ if (point) {
+ // We need to know whether the track is a constant zero weight.
+ // If it is so it wouldn't have a parameter block in the problem.
+ //
+ // Usually getting all markers of a track is considered slow, but this
+ // code is only used by the keyframe selection code where there aren't
+ // that many tracks in the storage and there are only 2 frames for each
+ // of the tracks.
+ vector<Marker> markera_of_track = tracks.MarkersForTrack(i);
+ for (int j = 0; j < markera_of_track.size(); j++) {
+ if (markera_of_track.at(j).weight != 0.0) {
+ minimized_points.push_back(point);
+ num_points++;
+ break;
}
}
}
+ }
- LG << "Number of cameras " << num_cameras;
- LG << "Number of points " << num_points;
+ LG << "Number of cameras " << num_cameras;
+ LG << "Number of points " << num_points;
- evaluation->num_cameras = num_cameras;
- evaluation->num_points = num_points;
+ evaluation->num_cameras = num_cameras;
+ evaluation->num_points = num_points;
- if (evaluation->evaluate_jacobian) { // Evaluate jacobian matrix.
- ceres::CRSMatrix evaluated_jacobian;
- ceres::Problem::EvaluateOptions eval_options;
+ if (evaluation->evaluate_jacobian) { // Evaluate jacobian matrix.
+ ceres::CRSMatrix evaluated_jacobian;
+ ceres::Problem::EvaluateOptions eval_options;
- // Cameras goes first in the ordering.
- int max_image = tracks.MaxImage();
- for (int i = 0; i <= max_image; i++) {
- const EuclideanCamera *camera = reconstruction->CameraForImage(i);
- if (camera) {
- double *current_camera_R_t = &(*all_cameras_R_t)[i](0);
+ // Cameras goes first in the ordering.
+ int max_image = tracks.MaxImage();
+ for (int i = 0; i <= max_image; i++) {
+ const EuclideanCamera *camera = reconstruction->CameraForImage(i);
+ if (camera) {
+ double *current_camera_R_t = &(*all_cameras_R_t)[i](0);
- // All cameras are variable now.
- problem->SetParameterBlockVariable(current_camera_R_t);
+ // All cameras are variable now.
+ problem->SetParameterBlockVariable(current_camera_R_t);
- eval_options.parameter_blocks.push_back(current_camera_R_t);
- }
+ eval_options.parameter_blocks.push_back(current_camera_R_t);
}
+ }
- // Points goes at the end of ordering,
- for (int i = 0; i < minimized_points.size(); i++) {
- EuclideanPoint *point = minimized_points.at(i);
- eval_options.parameter_blocks.push_back(&point->X(0));
- }
+ // Points goes at the end of ordering,
+ for (int i = 0; i < minimized_points.size(); i++) {
+ EuclideanPoint *point = minimized_points.at(i);
+ eval_options.parameter_blocks.push_back(&point->X(0));
+ }
- problem->Evaluate(eval_options,
- NULL, NULL, NULL,
- &evaluated_jacobian);
+ problem->Evaluate(eval_options,
+ NULL, NULL, NULL,
+ &evaluated_jacobian);
- CRSMatrixToEigenMatrix(evaluated_jacobian, &evaluation->jacobian);
- }
+ CRSMatrixToEigenMatrix(evaluated_jacobian, &evaluation->jacobian);
+ }
+}
+
+template<typename CostFunction>
+void AddResidualBlockToProblemImpl(const CameraIntrinsics *invariant_intrinsics,
+ double observed_x, double observed_y,
+ double weight,
+ double intrinsics_block[OFFSET_MAX],
+ double *camera_R_t,
+ EuclideanPoint *point,
+ ceres::Problem* problem) {
+ problem->AddResidualBlock(new ceres::AutoDiffCostFunction<
+ CostFunction, 2, OFFSET_MAX, 6, 3>(
+ new CostFunction(
+ invariant_intrinsics,
+ observed_x, observed_y,
+ weight)),
+ NULL,
+ intrinsics_block,
+ camera_R_t,
+ &point->X(0));
+}
+
+void AddResidualBlockToProblem(const CameraIntrinsics *invariant_intrinsics,
+ const Marker &marker,
+ double marker_weight,
+ double intrinsics_block[OFFSET_MAX],
+ double *camera_R_t,
+ EuclideanPoint *point,
+ ceres::Problem* problem) {
+ if (NeedUseInvertIntrinsicsPipeline(invariant_intrinsics)) {
+ AddResidualBlockToProblemImpl<ReprojectionErrorInvertIntrinsics>(
+ invariant_intrinsics,
+ marker.x, marker.y,
+ marker_weight,
+ intrinsics_block,
+ camera_R_t,
+ point,
+ problem);
+ } else {
+ AddResidualBlockToProblemImpl<ReprojectionErrorApplyIntrinsics>(
+ invariant_intrinsics,
+ marker.x, marker.y,
+ marker_weight,
+ intrinsics_block,
+ camera_R_t,
+ point,
+ problem);
+ }
}
// This is an utility function to only bundle 3D position of
@@ -375,10 +601,10 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks,
//
// At this point we only need to bundle points positions, cameras
// are to be totally still here.
-void EuclideanBundlePointsOnly(const DistortionModelType distortion_model,
+void EuclideanBundlePointsOnly(const CameraIntrinsics *invariant_intrinsics,
const vector<Marker> &markers,
vector<Vec6> &all_cameras_R_t,
- double ceres_intrinsics[OFFSET_MAX],
+ double intrinsics_block[OFFSET_MAX],
EuclideanReconstruction *reconstruction) {
ceres::Problem::Options problem_options;
ceres::Problem problem(problem_options);
@@ -392,20 +618,16 @@ void EuclideanBundlePointsOnly(const DistortionModelType distortion_model,
}
// Rotation of camera denoted in angle axis followed with
- // camera translaiton.
+ // camera translation.
double *current_camera_R_t = &all_cameras_R_t[camera->image](0);
- problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
- OpenCVReprojectionError, 2, OFFSET_MAX, 6, 3>(
- new OpenCVReprojectionError(
- distortion_model,
- marker.x,
- marker.y,
- 1.0)),
- NULL,
- ceres_intrinsics,
- current_camera_R_t,
- &point->X(0));
+ AddResidualBlockToProblem(invariant_intrinsics,
+ marker,
+ 1.0,
+ intrinsics_block,
+ current_camera_R_t,
+ point,
+ &problem);
problem.SetParameterBlockConstant(current_camera_R_t);
num_residuals++;
@@ -417,7 +639,7 @@ void EuclideanBundlePointsOnly(const DistortionModelType distortion_model,
return;
}
- problem.SetParameterBlockConstant(ceres_intrinsics);
+ problem.SetParameterBlockConstant(intrinsics_block);
// Configure the solver.
ceres::Solver::Options options;
@@ -438,7 +660,6 @@ void EuclideanBundlePointsOnly(const DistortionModelType distortion_model,
ceres::Solve(options, &problem, &summary);
LG << "Final report:\n" << summary.FullReport();
-
}
} // namespace
@@ -464,14 +685,14 @@ void EuclideanBundleCommonIntrinsics(
LG << "Original intrinsics: " << *intrinsics;
vector<Marker> markers = tracks.AllMarkers();
- // N-th element denotes whether track N is a constant zero-weigthed track.
+ // N-th element denotes whether track N is a constant zero-weighted track.
vector<bool> zero_weight_tracks_flags(tracks.MaxTrack() + 1, true);
// Residual blocks with 10 parameters are unwieldly with Ceres, so pack the
// intrinsics into a single block and rely on local parameterizations to
// control which intrinsics are allowed to vary.
- double ceres_intrinsics[OFFSET_MAX];
- PackIntrinisicsIntoArray(*intrinsics, ceres_intrinsics);
+ double intrinsics_block[OFFSET_MAX];
+ PackIntrinisicsIntoArray(*intrinsics, intrinsics_block);
// Convert cameras rotations to angle axis and merge with translation
// into single parameter block for maximal minimization speed.
@@ -509,24 +730,20 @@ void EuclideanBundleCommonIntrinsics(
}
// Rotation of camera denoted in angle axis followed with
- // camera translaiton.
+ // camera translation.
double *current_camera_R_t = &all_cameras_R_t[camera->image](0);
// Skip residual block for markers which does have absolutely
// no affect on the final solution.
// This way ceres is not gonna to go crazy.
if (marker.weight != 0.0) {
- problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
- OpenCVReprojectionError, 2, OFFSET_MAX, 6, 3>(
- new OpenCVReprojectionError(
- intrinsics->GetDistortionModelType(),
- marker.x,
- marker.y,
- marker.weight)),
- NULL,
- ceres_intrinsics,
- current_camera_R_t,
- &point->X(0));
+ AddResidualBlockToProblem(intrinsics,
+ marker,
+ marker.weight,
+ intrinsics_block,
+ current_camera_R_t,
+ point,
+ &problem);
// We lock the first camera to better deal with scene orientation ambiguity.
if (!have_locked_camera) {
@@ -561,7 +778,7 @@ void EuclideanBundleCommonIntrinsics(
if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
// No camera intrinsics are being refined,
// set the whole parameter block as constant for best performance.
- problem.SetParameterBlockConstant(ceres_intrinsics);
+ problem.SetParameterBlockConstant(intrinsics_block);
} else {
// Set the camera intrinsics that are not to be bundled as
// constant using some macro trickery.
@@ -586,7 +803,7 @@ void EuclideanBundleCommonIntrinsics(
ceres::SubsetParameterization *subset_parameterization =
new ceres::SubsetParameterization(OFFSET_MAX, constant_intrinsics);
- problem.SetParameterization(ceres_intrinsics, subset_parameterization);
+ problem.SetParameterization(intrinsics_block, subset_parameterization);
}
// Configure the solver.
@@ -616,7 +833,7 @@ void EuclideanBundleCommonIntrinsics(
// Copy intrinsics back.
if (bundle_intrinsics != BUNDLE_NO_INTRINSICS)
- UnpackIntrinsicsFromArray(ceres_intrinsics, intrinsics);
+ UnpackIntrinsicsFromArray(intrinsics_block, intrinsics);
LG << "Final intrinsics: " << *intrinsics;
@@ -641,10 +858,10 @@ void EuclideanBundleCommonIntrinsics(
if (zero_weight_markers.size()) {
LG << "Refining position of constant zero-weighted tracks";
- EuclideanBundlePointsOnly(intrinsics->GetDistortionModelType(),
+ EuclideanBundlePointsOnly(intrinsics,
zero_weight_markers,
all_cameras_R_t,
- ceres_intrinsics,
+ intrinsics_block,
reconstruction);
}
}
diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
index 5e4e07b3c4c..a95b394ad06 100644
--- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
@@ -131,6 +131,8 @@ void CameraIntrinsics::ResetLookupGrids() {
undistort_.Reset();
}
+// Polynomial model.
+
PolynomialCameraIntrinsics::PolynomialCameraIntrinsics()
: CameraIntrinsics() {
SetRadialDistortion(0.0, 0.0, 0.0);
@@ -193,6 +195,8 @@ void PolynomialCameraIntrinsics::InvertIntrinsics(
normalized_y);
}
+// Division model.
+
DivisionCameraIntrinsics::DivisionCameraIntrinsics()
: CameraIntrinsics() {
SetDistortion(0.0, 0.0);
@@ -241,6 +245,57 @@ void DivisionCameraIntrinsics::InvertIntrinsics(double image_x,
normalized_y);
}
+// Nuke model.
+
+NukeCameraIntrinsics::NukeCameraIntrinsics()
+ : CameraIntrinsics() {
+ SetDistortion(0.0, 0.0);
+}
+
+NukeCameraIntrinsics::NukeCameraIntrinsics(
+ const NukeCameraIntrinsics &from)
+ : CameraIntrinsics(from) {
+ SetDistortion(from.k1(), from.k1());
+}
+
+void NukeCameraIntrinsics::SetDistortion(double k1, double k2) {
+ parameters_[OFFSET_K1] = k1;
+ parameters_[OFFSET_K2] = k2;
+ ResetLookupGrids();
+}
+
+void NukeCameraIntrinsics::ApplyIntrinsics(double normalized_x,
+ double normalized_y,
+ double *image_x,
+ double *image_y) const {
+ ApplyNukeDistortionModel(focal_length_x(),
+ focal_length_y(),
+ principal_point_x(),
+ principal_point_y(),
+ image_width(), image_height(),
+ k1(), k2(),
+ normalized_x,
+ normalized_y,
+ image_x,
+ image_y);
+}
+
+void NukeCameraIntrinsics::InvertIntrinsics(double image_x,
+ double image_y,
+ double *normalized_x,
+ double *normalized_y) const {
+ InvertNukeDistortionModel(focal_length_x(),
+ focal_length_y(),
+ principal_point_x(),
+ principal_point_y(),
+ image_width(), image_height(),
+ k1(), k2(),
+ image_x,
+ image_y,
+ normalized_x,
+ normalized_y);
+}
+
std::ostream& operator <<(std::ostream &os,
const CameraIntrinsics &intrinsics) {
if (intrinsics.focal_length_x() == intrinsics.focal_length_x()) {
@@ -281,6 +336,14 @@ std::ostream& operator <<(std::ostream &os,
PRINT_NONZERO_COEFFICIENT(division_intrinsics, k2);
break;
}
+ case DISTORTION_MODEL_NUKE:
+ {
+ const NukeCameraIntrinsics *nuke_intrinsics =
+ static_cast<const NukeCameraIntrinsics *>(&intrinsics);
+ PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k1);
+ PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k2);
+ break;
+ }
default:
LOG(FATAL) << "Unknown distortion model.";
}
diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
index 6a3ade81089..782fd56c54c 100644
--- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
@@ -276,7 +276,7 @@ class CameraIntrinsics {
class PolynomialCameraIntrinsics : public CameraIntrinsics {
public:
// This constants defines an offset of corresponding coefficients
- // in the arameters_ array.
+ // in the parameters_ array.
enum {
OFFSET_K1,
OFFSET_K2,
@@ -342,7 +342,7 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics {
class DivisionCameraIntrinsics : public CameraIntrinsics {
public:
// This constants defines an offset of corresponding coefficients
- // in the arameters_ array.
+ // in the parameters_ array.
enum {
OFFSET_K1,
OFFSET_K2,
@@ -393,6 +393,60 @@ class DivisionCameraIntrinsics : public CameraIntrinsics {
double parameters_[NUM_PARAMETERS];
};
+class NukeCameraIntrinsics : public CameraIntrinsics {
+ public:
+ // This constants defines an offset of corresponding coefficients
+ // in the parameters_ array.
+ enum {
+ OFFSET_K1,
+ OFFSET_K2,
+
+ // This defines the size of array which we need to have in order
+ // to store all the coefficients.
+ NUM_PARAMETERS,
+ };
+
+ NukeCameraIntrinsics();
+ NukeCameraIntrinsics(const NukeCameraIntrinsics &from);
+
+ DistortionModelType GetDistortionModelType() const {
+ return DISTORTION_MODEL_NUKE;
+ }
+
+ int num_distortion_parameters() const { return NUM_PARAMETERS; }
+ double *distortion_parameters() { return parameters_; };
+ const double *distortion_parameters() const { return parameters_; };
+
+ double k1() const { return parameters_[OFFSET_K1]; }
+ double k2() const { return parameters_[OFFSET_K2]; }
+
+ // Set radial distortion coeffcients.
+ void SetDistortion(double k1, double k2);
+
+ // Apply camera intrinsics to the normalized point to get image coordinates.
+ //
+ // This applies the lens distortion to a point which is in normalized
+ // camera coordinates (i.e. the principal point is at (0, 0)) to get image
+ // coordinates in pixels.
+ void ApplyIntrinsics(double normalized_x,
+ double normalized_y,
+ double *image_x,
+ double *image_y) const;
+
+ // Invert camera intrinsics on the image point to get normalized coordinates.
+ //
+ // This reverses the effect of lens distortion on a point which is in image
+ // coordinates to get normalized camera coordinates.
+ void InvertIntrinsics(double image_x,
+ double image_y,
+ double *normalized_x,
+ double *normalized_y) const;
+
+ private:
+ // Double-parameter division distortion model.
+ double parameters_[NUM_PARAMETERS];
+};
+
/// A human-readable representation of the camera intrinsic parameters.
std::ostream& operator <<(std::ostream &os,
const CameraIntrinsics &intrinsics);
diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.cc b/intern/libmv/libmv/simple_pipeline/distortion_models.cc
index 9b6dca2678a..c069fc6f623 100644
--- a/intern/libmv/libmv/simple_pipeline/distortion_models.cc
+++ b/intern/libmv/libmv/simple_pipeline/distortion_models.cc
@@ -194,4 +194,96 @@ void InvertDivisionDistortionModel(const double focal_length_x,
*normalized_y = normalized(1);
}
+struct ApplyNukeIntrinsicsCostFunction {
+ public:
+ typedef Vec2 FMatrixType;
+ typedef Vec2 XMatrixType;
+
+ ApplyNukeIntrinsicsCostFunction(const double focal_length_x,
+ const double focal_length_y,
+ const double principal_point_x,
+ const double principal_point_y,
+ const int image_width,
+ const int image_height,
+ const double k1,
+ const double k2,
+ const double expected_normalized_x,
+ const double expected_normalized_y)
+ : focal_length_x_(focal_length_x),
+ focal_length_y_(focal_length_y),
+ principal_point_x_(principal_point_x),
+ principal_point_y_(principal_point_y),
+ image_width_(image_width),
+ image_height_(image_height),
+ k1_(k1), k2_(k2),
+ expected_normalized_x_(expected_normalized_x),
+ expected_normalized_y_(expected_normalized_y) {}
+
+ Vec2 operator()(const Vec2 &image_coordinate) const {
+ double actual_normalized_x, actual_normalized_y;
+
+ InvertNukeDistortionModel(focal_length_x_,
+ focal_length_y_,
+ principal_point_x_,
+ principal_point_y_,
+ image_width_, image_height_,
+ k1_, k2_,
+ image_coordinate(0), image_coordinate(1),
+ &actual_normalized_x, &actual_normalized_y);
+
+ Vec2 fx;
+ fx << (actual_normalized_x - expected_normalized_x_),
+ (actual_normalized_y - expected_normalized_y_);
+ return fx;
+ }
+ double focal_length_x_;
+ double focal_length_y_;
+ double principal_point_x_;
+ double principal_point_y_;
+ int image_width_;
+ int image_height_;
+ double k1_, k2_;
+ double expected_normalized_x_, expected_normalized_y_;
+};
+
+void ApplyNukeDistortionModel(const double focal_length_x,
+ const double focal_length_y,
+ const double principal_point_x,
+ const double principal_point_y,
+ const int image_width,
+ const int image_height,
+ const double k1,
+ const double k2,
+ const double normalized_x,
+ const double normalized_y,
+ double *image_x,
+ double *image_y) {
+ // Compute the initial guess. For a camera with no distortion, this will also
+ // be the final answer; the LM iteration will terminate immediately.
+ Vec2 image;
+ image(0) = normalized_x * focal_length_x + principal_point_x;
+ image(1) = normalized_y * focal_length_y + principal_point_y;
+
+ // TODO(sergey): Use Ceres minimizer instead.
+ typedef LevenbergMarquardt<ApplyNukeIntrinsicsCostFunction> Solver;
+
+ ApplyNukeIntrinsicsCostFunction intrinsics_cost(focal_length_x,
+ focal_length_y,
+ principal_point_x,
+ principal_point_y,
+ image_width,
+ image_height,
+ k1, k2,
+ normalized_x, normalized_y);
+ Solver::SolverParameters params;
+ Solver solver(intrinsics_cost);
+
+ /*Solver::Results results =*/ solver.minimize(params, &image);
+
+ // TODO(keir): Better error handling.
+
+ *image_x = image(0);
+ *image_y = image(1);
+}
+
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.h b/intern/libmv/libmv/simple_pipeline/distortion_models.h
index 4f8e2295a0e..6ba351d729d 100644
--- a/intern/libmv/libmv/simple_pipeline/distortion_models.h
+++ b/intern/libmv/libmv/simple_pipeline/distortion_models.h
@@ -21,11 +21,14 @@
#ifndef LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_
#define LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_
+#include <algorithm>
+
namespace libmv {
enum DistortionModelType {
DISTORTION_MODEL_POLYNOMIAL,
- DISTORTION_MODEL_DIVISION
+ DISTORTION_MODEL_DIVISION,
+ DISTORTION_MODEL_NUKE,
};
// Invert camera intrinsics on the image point to get normalized coordinates.
@@ -126,6 +129,79 @@ inline void ApplyDivisionDistortionModel(const T &focal_length_x,
*image_y = focal_length_y * yd + principal_point_y;
}
+// Invert camera intrinsics on the image point to get normalized coordinates.
+// This inverts the radial lens distortion to a point which is in image pixel
+// coordinates to get normalized coordinates.
+//
+// Uses Nuke distortion model.
+template <typename T>
+void InvertNukeDistortionModel(const T &focal_length_x,
+ const T &focal_length_y,
+ const T &principal_point_x,
+ const T &principal_point_y,
+ const int image_width,
+ const int image_height,
+ const T &k1,
+ const T &k2,
+ const T &image_x,
+ const T &image_y,
+ T *normalized_x,
+ T *normalized_y) {
+ // According to the documentation:
+ //
+ // xu = xd / (1 + k0 * rd^2 + k1 * rd^4)
+ // yu = yd / (1 + k0 * rd^2 + k1 * rd^4)
+ //
+ // Legend:
+ // (xd, yd) are the distorted cartesian coordinates,
+ // (rd, phid) are the distorted polar coordinates,
+ // (xu, yu) are the undistorted cartesian coordinates,
+ // (ru, phiu) are the undistorted polar coordinates,
+ // the k-values are the distortion coefficients.
+ //
+ // The coordinate systems are relative to the distortion centre.
+
+ const int max_image_size = std::max(image_width, image_height);
+ const double max_half_image_size = max_image_size * 0.5;
+
+ if (max_half_image_size == 0.0) {
+ *normalized_x = image_x * max_half_image_size / focal_length_x;
+ *normalized_y = image_y * max_half_image_size / focal_length_y;
+ return;
+ }
+
+ const T xd = (image_x - principal_point_x) / max_half_image_size;
+ const T yd = (image_y - principal_point_y) / max_half_image_size;
+
+ T rd2 = xd*xd + yd*yd;
+ T rd4 = rd2 * rd2;
+ T r_coeff = T(1) / (T(1) + k1*rd2 + k2*rd4);
+ T xu = xd * r_coeff;
+ T yu = yd * r_coeff;
+
+ *normalized_x = xu * max_half_image_size / focal_length_x;
+ *normalized_y = yu * max_half_image_size / focal_length_y;
+}
+
+// Apply camera intrinsics to the normalized point to get image coordinates.
+// This applies the radial lens distortion to a point which is in normalized
+// camera coordinates (i.e. the principal point is at (0, 0)) to get image
+// coordinates in pixels. Templated for use with autodifferentiation.
+//
+// Uses Nuke distortion model.
+void ApplyNukeDistortionModel(const double focal_length_x,
+ const double focal_length_y,
+ const double principal_point_x,
+ const double principal_point_y,
+ const int image_width,
+ const int image_height,
+ const double k1,
+ const double k2,
+ const double normalized_x,
+ const double normalized_y,
+ double *image_x,
+ double *image_y);
+
} // namespace libmv
#endif // LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_
diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp
index a56ce4c1f60..fd273b728e7 100644
--- a/intern/mantaflow/intern/MANTA_main.cpp
+++ b/intern/mantaflow/intern/MANTA_main.cpp
@@ -48,7 +48,16 @@
#include "MEM_guardedalloc.h"
-std::atomic<int> MANTA::solverID(0);
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::ifstream;
+using std::istringstream;
+using std::ofstream;
+using std::ostringstream;
+using std::to_string;
+
+atomic<int> MANTA::solverID(0);
int MANTA::with_debug(0);
/* Number of particles that the cache reads at once (with zlib). */
@@ -61,29 +70,30 @@ int MANTA::with_debug(0);
MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID)
{
if (with_debug)
- std::cout << "FLUID: " << mCurrentID << " with res(" << res[0] << ", " << res[1] << ", "
- << res[2] << ")" << std::endl;
-
- mmd->domain->fluid = this;
-
- mUsingLiquid = (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID);
- mUsingSmoke = (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS);
- mUsingNoise = (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE) && mUsingSmoke;
- mUsingFractions = (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid;
- mUsingMesh = (mmd->domain->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid;
- mUsingMVel = (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid;
- mUsingGuiding = (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDE);
- mUsingDrops = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid;
- mUsingBubbles = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) && mUsingLiquid;
- mUsingFloats = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) && mUsingLiquid;
- mUsingTracers = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) && mUsingLiquid;
-
- mUsingHeat = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) && mUsingSmoke;
- mUsingFire = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) && mUsingSmoke;
- mUsingColors = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) && mUsingSmoke;
- mUsingObstacle = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE);
- mUsingInvel = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL);
- mUsingOutflow = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW);
+ cout << "FLUID: " << mCurrentID << " with res(" << res[0] << ", " << res[1] << ", " << res[2]
+ << ")" << endl;
+
+ FluidDomainSettings *mds = mmd->domain;
+ mds->fluid = this;
+
+ mUsingLiquid = (mds->type == FLUID_DOMAIN_TYPE_LIQUID);
+ mUsingSmoke = (mds->type == FLUID_DOMAIN_TYPE_GAS);
+ mUsingNoise = (mds->flags & FLUID_DOMAIN_USE_NOISE) && mUsingSmoke;
+ mUsingFractions = (mds->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid;
+ mUsingMesh = (mds->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid;
+ mUsingMVel = (mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid;
+ mUsingGuiding = (mds->flags & FLUID_DOMAIN_USE_GUIDE);
+ mUsingDrops = (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid;
+ mUsingBubbles = (mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) && mUsingLiquid;
+ mUsingFloats = (mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) && mUsingLiquid;
+ mUsingTracers = (mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) && mUsingLiquid;
+
+ mUsingHeat = (mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) && mUsingSmoke;
+ mUsingFire = (mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) && mUsingSmoke;
+ mUsingColors = (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) && mUsingSmoke;
+ mUsingObstacle = (mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE);
+ mUsingInvel = (mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL);
+ mUsingOutflow = (mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW);
// Simulation constants
mTempAmb = 0; // TODO: Maybe use this later for buoyancy calculation
@@ -91,10 +101,8 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID)
mResY = res[1];
mResZ = res[2];
mMaxRes = MAX3(mResX, mResY, mResZ);
- mConstantScaling = 64.0f / mMaxRes;
- mConstantScaling = (mConstantScaling < 1.0f) ? 1.0f : mConstantScaling;
mTotalCells = mResX * mResY * mResZ;
- mResGuiding = mmd->domain->res;
+ mResGuiding = mds->res;
// Smoke low res grids
mDensity = nullptr;
@@ -184,86 +192,89 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID)
// Setup Mantaflow in Python
initializeMantaflow();
+ // Initializa RNA map with values that Python will need
+ initializeRNAMap(mmd);
+
// Initialize Mantaflow variables in Python
// Liquid
if (mUsingLiquid) {
- initDomain(mmd);
- initLiquid(mmd);
+ initDomain();
+ initLiquid();
if (mUsingObstacle)
- initObstacle(mmd);
+ initObstacle();
if (mUsingInvel)
- initInVelocity(mmd);
+ initInVelocity();
if (mUsingOutflow)
- initOutflow(mmd);
+ initOutflow();
if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) {
- mUpresParticle = mmd->domain->particle_scale;
+ mUpresParticle = mds->particle_scale;
mResXParticle = mUpresParticle * mResX;
mResYParticle = mUpresParticle * mResY;
mResZParticle = mUpresParticle * mResZ;
mTotalCellsParticles = mResXParticle * mResYParticle * mResZParticle;
- initSndParts(mmd);
- initLiquidSndParts(mmd);
+ initSndParts();
+ initLiquidSndParts();
}
if (mUsingMesh) {
- mUpresMesh = mmd->domain->mesh_scale;
+ mUpresMesh = mds->mesh_scale;
mResXMesh = mUpresMesh * mResX;
mResYMesh = mUpresMesh * mResY;
mResZMesh = mUpresMesh * mResZ;
mTotalCellsMesh = mResXMesh * mResYMesh * mResZMesh;
// Initialize Mantaflow variables in Python
- initMesh(mmd);
- initLiquidMesh(mmd);
+ initMesh();
+ initLiquidMesh();
}
if (mUsingGuiding) {
- mResGuiding = (mmd->domain->guide_parent) ? mmd->domain->guide_res : mmd->domain->res;
- initGuiding(mmd);
+ mResGuiding = (mds->guide_parent) ? mds->guide_res : mds->res;
+ initGuiding();
}
if (mUsingFractions) {
- initFractions(mmd);
+ initFractions();
}
}
// Smoke
if (mUsingSmoke) {
- initDomain(mmd);
- initSmoke(mmd);
+ initDomain();
+ initSmoke();
if (mUsingHeat)
- initHeat(mmd);
+ initHeat();
if (mUsingFire)
- initFire(mmd);
+ initFire();
if (mUsingColors)
- initColors(mmd);
+ initColors();
if (mUsingObstacle)
- initObstacle(mmd);
+ initObstacle();
if (mUsingInvel)
- initInVelocity(mmd);
+ initInVelocity();
if (mUsingOutflow)
- initOutflow(mmd);
+ initOutflow();
if (mUsingGuiding) {
- mResGuiding = (mmd->domain->guide_parent) ? mmd->domain->guide_res : mmd->domain->res;
- initGuiding(mmd);
+ mResGuiding = (mds->guide_parent) ? mds->guide_res : mds->res;
+ initGuiding();
}
if (mUsingNoise) {
- int amplify = mmd->domain->noise_scale;
+ int amplify = mds->noise_scale;
mResXNoise = amplify * mResX;
mResYNoise = amplify * mResY;
mResZNoise = amplify * mResZ;
mTotalCellsHigh = mResXNoise * mResYNoise * mResZNoise;
// Initialize Mantaflow variables in Python
- initNoise(mmd);
- initSmokeNoise(mmd);
+ initNoise();
+ initSmokeNoise();
if (mUsingFire)
- initFireHigh(mmd);
+ initFireHigh();
if (mUsingColors)
- initColorsHigh(mmd);
+ initColorsHigh();
}
}
updatePointers();
@@ -272,32 +283,32 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID)
void MANTA::initDomain(FluidModifierData *mmd)
{
// Vector will hold all python commands that are to be executed
- std::vector<std::string> pythonCommands;
+ vector<string> pythonCommands;
// Set manta debug level first
pythonCommands.push_back(manta_import + manta_debuglevel);
- std::ostringstream ss;
+ ostringstream ss;
ss << "set_manta_debuglevel(" << with_debug << ")";
pythonCommands.push_back(ss.str());
// Now init basic fluid domain
- std::string tmpString = fluid_variables + fluid_solver + fluid_alloc + fluid_cache_helper +
- fluid_bake_multiprocessing + fluid_bake_data + fluid_bake_noise +
- fluid_bake_mesh + fluid_bake_particles + fluid_bake_guiding +
- fluid_file_import + fluid_file_export + fluid_save_data +
- fluid_load_data + fluid_pre_step + fluid_post_step +
- fluid_adapt_time_step + fluid_time_stepping;
- std::string finalString = parseScript(tmpString, mmd);
+ string tmpString = fluid_variables + fluid_solver + fluid_alloc + fluid_cache_helper +
+ fluid_bake_multiprocessing + fluid_bake_data + fluid_bake_noise +
+ fluid_bake_mesh + fluid_bake_particles + fluid_bake_guiding +
+ fluid_file_import + fluid_file_export + fluid_save_data + fluid_load_data +
+ fluid_pre_step + fluid_post_step + fluid_adapt_time_step +
+ fluid_time_stepping;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
}
void MANTA::initNoise(FluidModifierData *mmd)
{
- std::vector<std::string> pythonCommands;
- std::string tmpString = fluid_variables_noise + fluid_solver_noise;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = fluid_variables_noise + fluid_solver_noise;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -305,10 +316,10 @@ void MANTA::initNoise(FluidModifierData *mmd)
void MANTA::initSmoke(FluidModifierData *mmd)
{
- std::vector<std::string> pythonCommands;
- std::string tmpString = smoke_variables + smoke_alloc + smoke_adaptive_step + smoke_save_data +
- smoke_load_data + smoke_step;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = smoke_variables + smoke_alloc + smoke_adaptive_step + smoke_save_data +
+ smoke_load_data + smoke_step;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -316,10 +327,10 @@ void MANTA::initSmoke(FluidModifierData *mmd)
void MANTA::initSmokeNoise(FluidModifierData *mmd)
{
- std::vector<std::string> pythonCommands;
- std::string tmpString = smoke_variables_noise + smoke_alloc_noise + smoke_wavelet_noise +
- smoke_save_noise + smoke_load_noise + smoke_step_noise;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = smoke_variables_noise + smoke_alloc_noise + smoke_wavelet_noise +
+ smoke_save_noise + smoke_load_noise + smoke_step_noise;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -329,9 +340,9 @@ void MANTA::initSmokeNoise(FluidModifierData *mmd)
void MANTA::initHeat(FluidModifierData *mmd)
{
if (!mHeat) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = smoke_alloc_heat + smoke_with_heat;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = smoke_alloc_heat + smoke_with_heat;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -342,9 +353,9 @@ void MANTA::initHeat(FluidModifierData *mmd)
void MANTA::initFire(FluidModifierData *mmd)
{
if (!mFuel) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = smoke_alloc_fire + smoke_with_fire;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = smoke_alloc_fire + smoke_with_fire;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -355,9 +366,9 @@ void MANTA::initFire(FluidModifierData *mmd)
void MANTA::initFireHigh(FluidModifierData *mmd)
{
if (!mFuelHigh) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = smoke_alloc_fire_noise + smoke_with_fire;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = smoke_alloc_fire_noise + smoke_with_fire;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -368,9 +379,9 @@ void MANTA::initFireHigh(FluidModifierData *mmd)
void MANTA::initColors(FluidModifierData *mmd)
{
if (!mColorR) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = smoke_alloc_colors + smoke_init_colors + smoke_with_colors;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = smoke_alloc_colors + smoke_init_colors + smoke_with_colors;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -381,9 +392,9 @@ void MANTA::initColors(FluidModifierData *mmd)
void MANTA::initColorsHigh(FluidModifierData *mmd)
{
if (!mColorRHigh) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = smoke_alloc_colors_noise + smoke_init_colors_noise + smoke_with_colors;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = smoke_alloc_colors_noise + smoke_init_colors_noise + smoke_with_colors;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -394,10 +405,10 @@ void MANTA::initColorsHigh(FluidModifierData *mmd)
void MANTA::initLiquid(FluidModifierData *mmd)
{
if (!mPhiIn) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = liquid_variables + liquid_alloc + liquid_init_phi + liquid_save_data +
- liquid_load_data + liquid_adaptive_step + liquid_step;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = liquid_variables + liquid_alloc + liquid_init_phi + liquid_save_data +
+ liquid_load_data + liquid_adaptive_step + liquid_step;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -407,9 +418,9 @@ void MANTA::initLiquid(FluidModifierData *mmd)
void MANTA::initMesh(FluidModifierData *mmd)
{
- std::vector<std::string> pythonCommands;
- std::string tmpString = fluid_variables_mesh + fluid_solver_mesh + liquid_load_mesh;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = fluid_variables_mesh + fluid_solver_mesh + liquid_load_mesh;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -418,9 +429,9 @@ void MANTA::initMesh(FluidModifierData *mmd)
void MANTA::initLiquidMesh(FluidModifierData *mmd)
{
- std::vector<std::string> pythonCommands;
- std::string tmpString = liquid_alloc_mesh + liquid_step_mesh + liquid_save_mesh;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = liquid_alloc_mesh + liquid_step_mesh + liquid_save_mesh;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -430,9 +441,9 @@ void MANTA::initLiquidMesh(FluidModifierData *mmd)
void MANTA::initObstacle(FluidModifierData *mmd)
{
if (!mPhiObsIn) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = fluid_alloc_obstacle + fluid_with_obstacle;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = fluid_alloc_obstacle + fluid_with_obstacle;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -443,10 +454,10 @@ void MANTA::initObstacle(FluidModifierData *mmd)
void MANTA::initGuiding(FluidModifierData *mmd)
{
if (!mPhiGuideIn) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = fluid_variables_guiding + fluid_solver_guiding + fluid_alloc_guiding +
- fluid_save_guiding + fluid_load_vel + fluid_load_guiding;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = fluid_variables_guiding + fluid_solver_guiding + fluid_alloc_guiding +
+ fluid_save_guiding + fluid_load_vel + fluid_load_guiding;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -456,9 +467,9 @@ void MANTA::initGuiding(FluidModifierData *mmd)
void MANTA::initFractions(FluidModifierData *mmd)
{
- std::vector<std::string> pythonCommands;
- std::string tmpString = fluid_alloc_fractions + fluid_with_fractions;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = fluid_alloc_fractions + fluid_with_fractions;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -468,9 +479,9 @@ void MANTA::initFractions(FluidModifierData *mmd)
void MANTA::initInVelocity(FluidModifierData *mmd)
{
if (!mInVelocityX) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = fluid_alloc_invel + fluid_with_invel;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = fluid_alloc_invel + fluid_with_invel;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -481,9 +492,9 @@ void MANTA::initInVelocity(FluidModifierData *mmd)
void MANTA::initOutflow(FluidModifierData *mmd)
{
if (!mPhiOutIn) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = fluid_alloc_outflow + fluid_with_outflow;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = fluid_alloc_outflow + fluid_with_outflow;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -493,9 +504,9 @@ void MANTA::initOutflow(FluidModifierData *mmd)
void MANTA::initSndParts(FluidModifierData *mmd)
{
- std::vector<std::string> pythonCommands;
- std::string tmpString = fluid_variables_particles + fluid_solver_particles;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = fluid_variables_particles + fluid_solver_particles;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -504,11 +515,11 @@ void MANTA::initSndParts(FluidModifierData *mmd)
void MANTA::initLiquidSndParts(FluidModifierData *mmd)
{
if (!mSndParticleData) {
- std::vector<std::string> pythonCommands;
- std::string tmpString = liquid_alloc_particles + liquid_variables_particles +
- liquid_step_particles + fluid_with_sndparts + liquid_load_particles +
- liquid_save_particles;
- std::string finalString = parseScript(tmpString, mmd);
+ vector<string> pythonCommands;
+ string tmpString = liquid_alloc_particles + liquid_variables_particles +
+ liquid_step_particles + fluid_with_sndparts + liquid_load_particles +
+ liquid_save_particles;
+ string finalString = parseScript(tmpString, mmd);
pythonCommands.push_back(finalString);
runPythonString(pythonCommands);
@@ -518,19 +529,22 @@ void MANTA::initLiquidSndParts(FluidModifierData *mmd)
MANTA::~MANTA()
{
if (with_debug)
- std::cout << "~FLUID: " << mCurrentID << " with res(" << mResX << ", " << mResY << ", "
- << mResZ << ")" << std::endl;
+ cout << "~FLUID: " << mCurrentID << " with res(" << mResX << ", " << mResY << ", " << mResZ
+ << ")" << endl;
// Destruction string for Python
- std::string tmpString = "";
- std::vector<std::string> pythonCommands;
+ string tmpString = "";
+ vector<string> pythonCommands;
bool result = false;
tmpString += manta_import;
tmpString += fluid_delete_all;
+ // Initializa RNA map with values that Python will need
+ initializeRNAMap();
+
// Leave out mmd argument in parseScript since only looking up IDs
- std::string finalString = parseScript(tmpString);
+ string finalString = parseScript(tmpString);
pythonCommands.push_back(finalString);
result = runPythonString(pythonCommands);
@@ -538,12 +552,12 @@ MANTA::~MANTA()
(void)result; // not needed in release
}
-bool MANTA::runPythonString(std::vector<std::string> commands)
+bool MANTA::runPythonString(vector<string> commands)
{
int success = -1;
PyGILState_STATE gilstate = PyGILState_Ensure();
- for (std::vector<std::string>::iterator it = commands.begin(); it != commands.end(); ++it) {
- std::string command = *it;
+ for (vector<string>::iterator it = commands.begin(); it != commands.end(); ++it) {
+ string command = *it;
#ifdef WIN32
// special treatment for windows when running python code
@@ -568,10 +582,10 @@ bool MANTA::runPythonString(std::vector<std::string> commands)
void MANTA::initializeMantaflow()
{
if (with_debug)
- std::cout << "Fluid: Initializing Mantaflow framework" << std::endl;
+ cout << "Fluid: Initializing Mantaflow framework" << endl;
- std::string filename = "manta_scene_" + std::to_string(mCurrentID) + ".py";
- std::vector<std::string> fill = std::vector<std::string>();
+ string filename = "manta_scene_" + to_string(mCurrentID) + ".py";
+ vector<string> fill = vector<string>();
// Initialize extension classes and wrappers
srand(0);
@@ -583,17 +597,17 @@ void MANTA::initializeMantaflow()
void MANTA::terminateMantaflow()
{
if (with_debug)
- std::cout << "Fluid: Releasing Mantaflow framework" << std::endl;
+ cout << "Fluid: Releasing Mantaflow framework" << endl;
PyGILState_STATE gilstate = PyGILState_Ensure();
Pb::finalize(); // Namespace from Mantaflow (registry)
PyGILState_Release(gilstate);
}
-static std::string getCacheFileEnding(char cache_format)
+static string getCacheFileEnding(char cache_format)
{
if (MANTA::with_debug)
- std::cout << "MANTA::getCacheFileEnding()" << std::endl;
+ cout << "MANTA::getCacheFileEnding()" << endl;
switch (cache_format) {
case FLUID_DOMAIN_FILE_UNI:
@@ -607,409 +621,237 @@ static std::string getCacheFileEnding(char cache_format)
case FLUID_DOMAIN_FILE_OBJECT:
return FLUID_DOMAIN_EXTENSION_OBJ;
default:
- std::cerr << "Fluid Error -- Could not find file extension. Using default file extension."
- << std::endl;
+ cerr << "Fluid Error -- Could not find file extension. Using default file extension."
+ << endl;
return FLUID_DOMAIN_EXTENSION_UNI;
}
}
-std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *mmd)
+static string getBooleanString(int value)
{
- std::ostringstream ss;
- bool is2D = false;
- int tmpVar;
- float tmpFloat;
+ return (value) ? "True" : "False";
+}
- if (varName == "ID") {
- ss << mCurrentID;
- return ss.str();
- }
+void MANTA::initializeRNAMap(FluidModifierData *mmd)
+{
+ if (with_debug)
+ cout << "MANTA::initializeRNAMap()" << endl;
+
+ mRNAMap["ID"] = to_string(mCurrentID);
if (!mmd) {
- std::cerr << "Fluid Error -- Invalid modifier data." << std::endl;
- ss << "ERROR - INVALID MODIFIER DATA";
- return ss.str();
- }
-
- is2D = (mmd->domain->solver_res == 2);
-
- if (varName == "USING_SMOKE")
- ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) ? "True" : "False");
- else if (varName == "USING_LIQUID")
- ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) ? "True" : "False");
- else if (varName == "USING_COLORS")
- ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS ? "True" : "False");
- else if (varName == "USING_HEAT")
- ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT ? "True" : "False");
- else if (varName == "USING_FIRE")
- ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE ? "True" : "False");
- else if (varName == "USING_NOISE")
- ss << (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE ? "True" : "False");
- else if (varName == "USING_OBSTACLE")
- ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE ? "True" : "False");
- else if (varName == "USING_GUIDING")
- ss << (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDE ? "True" : "False");
- else if (varName == "USING_INVEL")
- ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL ? "True" : "False");
- else if (varName == "USING_OUTFLOW")
- ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW ? "True" : "False");
- else if (varName == "USING_LOG_DISSOLVE")
- ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG ? "True" : "False");
- else if (varName == "USING_DISSOLVE")
- ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE ? "True" : "False");
- else if (varName == "SOLVER_DIM")
- ss << mmd->domain->solver_res;
- else if (varName == "DO_OPEN") {
- tmpVar = (FLUID_DOMAIN_BORDER_BACK | FLUID_DOMAIN_BORDER_FRONT | FLUID_DOMAIN_BORDER_LEFT |
- FLUID_DOMAIN_BORDER_RIGHT | FLUID_DOMAIN_BORDER_BOTTOM | FLUID_DOMAIN_BORDER_TOP);
- ss << (((mmd->domain->border_collisions & tmpVar) == tmpVar) ? "False" : "True");
- }
- else if (varName == "BOUND_CONDITIONS") {
- if (mmd->domain->solver_res == 2) {
- if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0)
- ss << "x";
- if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0)
- ss << "X";
- if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0)
- ss << "y";
- if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0)
- ss << "Y";
- }
- if (mmd->domain->solver_res == 3) {
- if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0)
- ss << "x";
- if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0)
- ss << "X";
- if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0)
- ss << "y";
- if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0)
- ss << "Y";
- if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BOTTOM) == 0)
- ss << "z";
- if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_TOP) == 0)
- ss << "Z";
- }
- }
- else if (varName == "BOUNDARY_WIDTH")
- ss << mmd->domain->boundary_width;
- else if (varName == "RES")
- ss << mMaxRes;
- else if (varName == "RESX")
- ss << mResX;
- else if (varName == "RESY")
- if (is2D) {
- ss << mResZ;
- }
- else {
- ss << mResY;
- }
- else if (varName == "RESZ") {
- if (is2D) {
- ss << 1;
- }
- else {
- ss << mResZ;
- }
- }
- else if (varName == "FRAME_LENGTH")
- ss << mmd->domain->frame_length;
- else if (varName == "CFL")
- ss << mmd->domain->cfl_condition;
- else if (varName == "DT")
- ss << mmd->domain->dt;
- else if (varName == "TIMESTEPS_MIN")
- ss << mmd->domain->timesteps_minimum;
- else if (varName == "TIMESTEPS_MAX")
- ss << mmd->domain->timesteps_maximum;
- else if (varName == "TIME_TOTAL")
- ss << mmd->domain->time_total;
- else if (varName == "TIME_PER_FRAME")
- ss << mmd->domain->time_per_frame;
- else if (varName == "VORTICITY")
- ss << mmd->domain->vorticity / mConstantScaling;
- else if (varName == "FLAME_VORTICITY")
- ss << mmd->domain->flame_vorticity / mConstantScaling;
- else if (varName == "NOISE_SCALE")
- ss << mmd->domain->noise_scale;
- else if (varName == "MESH_SCALE")
- ss << mmd->domain->mesh_scale;
- else if (varName == "PARTICLE_SCALE")
- ss << mmd->domain->particle_scale;
- else if (varName == "NOISE_RESX")
- ss << mResXNoise;
- else if (varName == "NOISE_RESY") {
- if (is2D) {
- ss << mResZNoise;
- }
- else {
- ss << mResYNoise;
- }
- }
- else if (varName == "NOISE_RESZ") {
- if (is2D) {
- ss << 1;
- }
- else {
- ss << mResZNoise;
- }
- }
- else if (varName == "MESH_RESX")
- ss << mResXMesh;
- else if (varName == "MESH_RESY") {
- if (is2D) {
- ss << mResZMesh;
- }
- else {
- ss << mResYMesh;
- }
- }
- else if (varName == "MESH_RESZ") {
- if (is2D) {
- ss << 1;
- }
- else {
- ss << mResZMesh;
- }
- }
- else if (varName == "PARTICLE_RESX")
- ss << mResXParticle;
- else if (varName == "PARTICLE_RESY") {
- if (is2D) {
- ss << mResZParticle;
- }
- else {
- ss << mResYParticle;
- }
- }
- else if (varName == "PARTICLE_RESZ") {
- if (is2D) {
- ss << 1;
- }
- else {
- ss << mResZParticle;
- }
- }
- else if (varName == "GUIDING_RESX")
- ss << mResGuiding[0];
- else if (varName == "GUIDING_RESY") {
- if (is2D) {
- ss << mResGuiding[2];
- }
- else {
- ss << mResGuiding[1];
- }
+ if (with_debug)
+ cout << "No modifier data given in RNA map setup - returning early" << endl;
+ return;
}
- else if (varName == "GUIDING_RESZ") {
- if (is2D) {
- ss << 1;
- }
- else {
- ss << mResGuiding[2];
- }
+
+ FluidDomainSettings *mds = mmd->domain;
+ bool is2D = (mds->solver_res == 2);
+
+ string borderCollisions = "";
+ if ((mds->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0)
+ borderCollisions += "x";
+ if ((mds->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0)
+ borderCollisions += "X";
+ if ((mds->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0)
+ borderCollisions += "y";
+ if ((mds->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0)
+ borderCollisions += "Y";
+ if ((mds->border_collisions & FLUID_DOMAIN_BORDER_BOTTOM) == 0)
+ borderCollisions += "z";
+ if ((mds->border_collisions & FLUID_DOMAIN_BORDER_TOP) == 0)
+ borderCollisions += "Z";
+
+ string simulationMethod = "";
+ if (mds->simulation_method & FLUID_DOMAIN_METHOD_FLIP)
+ simulationMethod += "'FLIP'";
+ else if (mds->simulation_method & FLUID_DOMAIN_METHOD_APIC)
+ simulationMethod += "'APIC'";
+
+ string particleTypesStr = "";
+ if (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY)
+ particleTypesStr += "PtypeSpray";
+ if (mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) {
+ if (!particleTypesStr.empty())
+ particleTypesStr += "|";
+ particleTypesStr += "PtypeBubble";
+ }
+ if (mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) {
+ if (!particleTypesStr.empty())
+ particleTypesStr += "|";
+ particleTypesStr += "PtypeFoam";
+ }
+ if (mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) {
+ if (!particleTypesStr.empty())
+ particleTypesStr += "|";
+ particleTypesStr += "PtypeTracer";
+ }
+ if (particleTypesStr.empty())
+ particleTypesStr = "0";
+
+ int particleTypes = (FLUID_DOMAIN_PARTICLE_SPRAY | FLUID_DOMAIN_PARTICLE_BUBBLE |
+ FLUID_DOMAIN_PARTICLE_FOAM | FLUID_DOMAIN_PARTICLE_TRACER);
+
+ string cacheDirectory(mds->cache_directory);
+
+ float viscosity = mds->viscosity_base * pow(10.0f, -mds->viscosity_exponent);
+ float domainSize = MAX3(mds->global_size[0], mds->global_size[1], mds->global_size[2]);
+
+ mRNAMap["USING_SMOKE"] = getBooleanString(mds->type == FLUID_DOMAIN_TYPE_GAS);
+ mRNAMap["USING_LIQUID"] = getBooleanString(mds->type == FLUID_DOMAIN_TYPE_LIQUID);
+ mRNAMap["USING_COLORS"] = getBooleanString(mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS);
+ mRNAMap["USING_HEAT"] = getBooleanString(mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT);
+ mRNAMap["USING_FIRE"] = getBooleanString(mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE);
+ mRNAMap["USING_NOISE"] = getBooleanString(mds->flags & FLUID_DOMAIN_USE_NOISE);
+ mRNAMap["USING_OBSTACLE"] = getBooleanString(mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE);
+ mRNAMap["USING_GUIDING"] = getBooleanString(mds->flags & FLUID_DOMAIN_USE_GUIDE);
+ mRNAMap["USING_INVEL"] = getBooleanString(mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL);
+ mRNAMap["USING_OUTFLOW"] = getBooleanString(mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW);
+ mRNAMap["USING_LOG_DISSOLVE"] = getBooleanString(mds->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG);
+ mRNAMap["USING_DISSOLVE"] = getBooleanString(mds->flags & FLUID_DOMAIN_USE_DISSOLVE);
+ mRNAMap["DO_OPEN"] = getBooleanString(mds->border_collisions == 0);
+ mRNAMap["CACHE_RESUMABLE"] = getBooleanString(mds->cache_type != FLUID_DOMAIN_CACHE_FINAL);
+ mRNAMap["USING_ADAPTIVETIME"] = getBooleanString(mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME);
+ mRNAMap["USING_SPEEDVECTORS"] = getBooleanString(mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS);
+ mRNAMap["USING_FRACTIONS"] = getBooleanString(mds->flags & FLUID_DOMAIN_USE_FRACTIONS);
+ mRNAMap["DELETE_IN_OBSTACLE"] = getBooleanString(mds->flags & FLUID_DOMAIN_DELETE_IN_OBSTACLE);
+ mRNAMap["USING_DIFFUSION"] = getBooleanString(mds->flags & FLUID_DOMAIN_USE_DIFFUSION);
+ mRNAMap["USING_MESH"] = getBooleanString(mds->flags & FLUID_DOMAIN_USE_MESH);
+ mRNAMap["USING_IMPROVED_MESH"] = getBooleanString(mds->mesh_generator ==
+ FLUID_DOMAIN_MESH_IMPROVED);
+ mRNAMap["USING_SNDPARTS"] = getBooleanString(mds->particle_type & particleTypes);
+ mRNAMap["SNDPARTICLE_BOUNDARY_DELETE"] = getBooleanString(mds->sndparticle_boundary ==
+ SNDPARTICLE_BOUNDARY_DELETE);
+ mRNAMap["SNDPARTICLE_BOUNDARY_PUSHOUT"] = getBooleanString(mds->sndparticle_boundary ==
+ SNDPARTICLE_BOUNDARY_PUSHOUT);
+
+ mRNAMap["SOLVER_DIM"] = to_string(mds->solver_res);
+ mRNAMap["BOUND_CONDITIONS"] = borderCollisions;
+ mRNAMap["BOUNDARY_WIDTH"] = to_string(mds->boundary_width);
+ mRNAMap["RES"] = to_string(mMaxRes);
+ mRNAMap["RESX"] = to_string(mResX);
+ mRNAMap["RESY"] = (is2D) ? to_string(mResZ) : to_string(mResY);
+ mRNAMap["RESZ"] = (is2D) ? to_string(1) : to_string(mResZ);
+ mRNAMap["TIME_SCALE"] = to_string(mds->time_scale);
+ mRNAMap["FRAME_LENGTH"] = to_string(mds->frame_length);
+ mRNAMap["CFL"] = to_string(mds->cfl_condition);
+ mRNAMap["DT"] = to_string(mds->dt);
+ mRNAMap["TIMESTEPS_MIN"] = to_string(mds->timesteps_minimum);
+ mRNAMap["TIMESTEPS_MAX"] = to_string(mds->timesteps_maximum);
+ mRNAMap["TIME_TOTAL"] = to_string(mds->time_total);
+ mRNAMap["TIME_PER_FRAME"] = to_string(mds->time_per_frame);
+ mRNAMap["VORTICITY"] = to_string(mds->vorticity);
+ mRNAMap["FLAME_VORTICITY"] = to_string(mds->flame_vorticity);
+ mRNAMap["NOISE_SCALE"] = to_string(mds->noise_scale);
+ mRNAMap["MESH_SCALE"] = to_string(mds->mesh_scale);
+ mRNAMap["PARTICLE_SCALE"] = to_string(mds->particle_scale);
+ mRNAMap["NOISE_RESX"] = to_string(mResXNoise);
+ mRNAMap["NOISE_RESY"] = (is2D) ? to_string(mResZNoise) : to_string(mResYNoise);
+ mRNAMap["NOISE_RESZ"] = (is2D) ? to_string(1) : to_string(mResZNoise);
+ mRNAMap["MESH_RESX"] = to_string(mResXMesh);
+ mRNAMap["MESH_RESY"] = (is2D) ? to_string(mResZMesh) : to_string(mResYMesh);
+ mRNAMap["MESH_RESZ"] = (is2D) ? to_string(1) : to_string(mResZMesh);
+ mRNAMap["PARTICLE_RESX"] = to_string(mResXParticle);
+ mRNAMap["PARTICLE_RESY"] = (is2D) ? to_string(mResZParticle) : to_string(mResYParticle);
+ mRNAMap["PARTICLE_RESZ"] = (is2D) ? to_string(1) : to_string(mResZParticle);
+ mRNAMap["GUIDING_RESX"] = to_string(mResGuiding[0]);
+ mRNAMap["GUIDING_RESY"] = (is2D) ? to_string(mResGuiding[2]) : to_string(mResGuiding[1]);
+ mRNAMap["GUIDING_RESZ"] = (is2D) ? to_string(1) : to_string(mResGuiding[2]);
+ mRNAMap["MIN_RESX"] = to_string(mds->res_min[0]);
+ mRNAMap["MIN_RESY"] = to_string(mds->res_min[1]);
+ mRNAMap["MIN_RESZ"] = to_string(mds->res_min[2]);
+ mRNAMap["BASE_RESX"] = to_string(mds->base_res[0]);
+ mRNAMap["BASE_RESY"] = to_string(mds->base_res[1]);
+ mRNAMap["BASE_RESZ"] = to_string(mds->base_res[2]);
+ mRNAMap["WLT_STR"] = to_string(mds->noise_strength);
+ mRNAMap["NOISE_POSSCALE"] = to_string(mds->noise_pos_scale);
+ mRNAMap["NOISE_TIMEANIM"] = to_string(mds->noise_time_anim);
+ mRNAMap["COLOR_R"] = to_string(mds->active_color[0]);
+ mRNAMap["COLOR_G"] = to_string(mds->active_color[1]);
+ mRNAMap["COLOR_B"] = to_string(mds->active_color[2]);
+ mRNAMap["BUOYANCY_ALPHA"] = to_string(mds->alpha);
+ mRNAMap["BUOYANCY_BETA"] = to_string(mds->beta);
+ mRNAMap["DISSOLVE_SPEED"] = to_string(mds->diss_speed);
+ mRNAMap["BURNING_RATE"] = to_string(mds->burning_rate);
+ mRNAMap["FLAME_SMOKE"] = to_string(mds->flame_smoke);
+ mRNAMap["IGNITION_TEMP"] = to_string(mds->flame_ignition);
+ mRNAMap["MAX_TEMP"] = to_string(mds->flame_max_temp);
+ mRNAMap["FLAME_SMOKE_COLOR_X"] = to_string(mds->flame_smoke_color[0]);
+ mRNAMap["FLAME_SMOKE_COLOR_Y"] = to_string(mds->flame_smoke_color[1]);
+ mRNAMap["FLAME_SMOKE_COLOR_Z"] = to_string(mds->flame_smoke_color[2]);
+ mRNAMap["CURRENT_FRAME"] = to_string(mmd->time);
+ mRNAMap["START_FRAME"] = to_string(mds->cache_frame_start);
+ mRNAMap["END_FRAME"] = to_string(mds->cache_frame_end);
+ mRNAMap["CACHE_DATA_FORMAT"] = to_string(mds->cache_data_format);
+ mRNAMap["CACHE_MESH_FORMAT"] = to_string(mds->cache_mesh_format);
+ mRNAMap["CACHE_NOISE_FORMAT"] = to_string(mds->cache_noise_format);
+ mRNAMap["CACHE_PARTICLE_FORMAT"] = to_string(mds->cache_particle_format);
+ mRNAMap["SIMULATION_METHOD"] = simulationMethod;
+ mRNAMap["FLIP_RATIO"] = to_string(mds->flip_ratio);
+ mRNAMap["PARTICLE_RANDOMNESS"] = to_string(mds->particle_randomness);
+ mRNAMap["PARTICLE_NUMBER"] = to_string(mds->particle_number);
+ mRNAMap["PARTICLE_MINIMUM"] = to_string(mds->particle_minimum);
+ mRNAMap["PARTICLE_MAXIMUM"] = to_string(mds->particle_maximum);
+ mRNAMap["PARTICLE_RADIUS"] = to_string(mds->particle_radius);
+ mRNAMap["FRACTIONS_THRESHOLD"] = to_string(mds->fractions_threshold);
+ mRNAMap["MESH_CONCAVE_UPPER"] = to_string(mds->mesh_concave_upper);
+ mRNAMap["MESH_CONCAVE_LOWER"] = to_string(mds->mesh_concave_lower);
+ mRNAMap["MESH_PARTICLE_RADIUS"] = to_string(mds->mesh_particle_radius);
+ mRNAMap["MESH_SMOOTHEN_POS"] = to_string(mds->mesh_smoothen_pos);
+ mRNAMap["MESH_SMOOTHEN_NEG"] = to_string(mds->mesh_smoothen_neg);
+ mRNAMap["PARTICLE_BAND_WIDTH"] = to_string(mds->particle_band_width);
+ mRNAMap["SNDPARTICLE_TAU_MIN_WC"] = to_string(mds->sndparticle_tau_min_wc);
+ mRNAMap["SNDPARTICLE_TAU_MAX_WC"] = to_string(mds->sndparticle_tau_max_wc);
+ mRNAMap["SNDPARTICLE_TAU_MIN_TA"] = to_string(mds->sndparticle_tau_min_ta);
+ mRNAMap["SNDPARTICLE_TAU_MAX_TA"] = to_string(mds->sndparticle_tau_max_ta);
+ mRNAMap["SNDPARTICLE_TAU_MIN_K"] = to_string(mds->sndparticle_tau_min_k);
+ mRNAMap["SNDPARTICLE_TAU_MAX_K"] = to_string(mds->sndparticle_tau_max_k);
+ mRNAMap["SNDPARTICLE_K_WC"] = to_string(mds->sndparticle_k_wc);
+ mRNAMap["SNDPARTICLE_K_TA"] = to_string(mds->sndparticle_k_ta);
+ mRNAMap["SNDPARTICLE_K_B"] = to_string(mds->sndparticle_k_b);
+ mRNAMap["SNDPARTICLE_K_D"] = to_string(mds->sndparticle_k_d);
+ mRNAMap["SNDPARTICLE_L_MIN"] = to_string(mds->sndparticle_l_min);
+ mRNAMap["SNDPARTICLE_L_MAX"] = to_string(mds->sndparticle_l_max);
+ mRNAMap["SNDPARTICLE_POTENTIAL_RADIUS"] = to_string(mds->sndparticle_potential_radius);
+ mRNAMap["SNDPARTICLE_UPDATE_RADIUS"] = to_string(mds->sndparticle_update_radius);
+ mRNAMap["LIQUID_SURFACE_TENSION"] = to_string(mds->surface_tension);
+ mRNAMap["FLUID_VISCOSITY"] = to_string(viscosity);
+ mRNAMap["FLUID_DOMAIN_SIZE"] = to_string(domainSize);
+ mRNAMap["SNDPARTICLE_TYPES"] = particleTypesStr;
+ mRNAMap["GUIDING_ALPHA"] = to_string(mds->guide_alpha);
+ mRNAMap["GUIDING_BETA"] = to_string(mds->guide_beta);
+ mRNAMap["GUIDING_FACTOR"] = to_string(mds->guide_vel_factor);
+ mRNAMap["GRAVITY_X"] = to_string(mds->gravity[0]);
+ mRNAMap["GRAVITY_Y"] = to_string(mds->gravity[1]);
+ mRNAMap["GRAVITY_Z"] = to_string(mds->gravity[2]);
+ mRNAMap["CACHE_DIR"] = cacheDirectory;
+}
+
+string MANTA::getRealValue(const string &varName)
+{
+ if (with_debug)
+ cout << "MANTA::getRealValue()" << endl;
+
+ unordered_map<string, string>::iterator it;
+ it = mRNAMap.find(varName);
+
+ if (it == mRNAMap.end()) {
+ cerr << "Fluid Error -- variable " << varName << " not found in RNA map " << it->second
+ << endl;
+ return "";
}
- else if (varName == "MIN_RESX")
- ss << mmd->domain->res_min[0];
- else if (varName == "MIN_RESY")
- ss << mmd->domain->res_min[1];
- else if (varName == "MIN_RESZ")
- ss << mmd->domain->res_min[2];
- else if (varName == "BASE_RESX")
- ss << mmd->domain->base_res[0];
- else if (varName == "BASE_RESY")
- ss << mmd->domain->base_res[1];
- else if (varName == "BASE_RESZ")
- ss << mmd->domain->base_res[2];
- else if (varName == "WLT_STR")
- ss << mmd->domain->noise_strength;
- else if (varName == "NOISE_POSSCALE")
- ss << mmd->domain->noise_pos_scale;
- else if (varName == "NOISE_TIMEANIM")
- ss << mmd->domain->noise_time_anim;
- else if (varName == "COLOR_R")
- ss << mmd->domain->active_color[0];
- else if (varName == "COLOR_G")
- ss << mmd->domain->active_color[1];
- else if (varName == "COLOR_B")
- ss << mmd->domain->active_color[2];
- else if (varName == "BUOYANCY_ALPHA")
- ss << mmd->domain->alpha;
- else if (varName == "BUOYANCY_BETA")
- ss << mmd->domain->beta;
- else if (varName == "DISSOLVE_SPEED")
- ss << mmd->domain->diss_speed;
- else if (varName == "BURNING_RATE")
- ss << mmd->domain->burning_rate;
- else if (varName == "FLAME_SMOKE")
- ss << mmd->domain->flame_smoke;
- else if (varName == "IGNITION_TEMP")
- ss << mmd->domain->flame_ignition;
- else if (varName == "MAX_TEMP")
- ss << mmd->domain->flame_max_temp;
- else if (varName == "FLAME_SMOKE_COLOR_X")
- ss << mmd->domain->flame_smoke_color[0];
- else if (varName == "FLAME_SMOKE_COLOR_Y")
- ss << mmd->domain->flame_smoke_color[1];
- else if (varName == "FLAME_SMOKE_COLOR_Z")
- ss << mmd->domain->flame_smoke_color[2];
- else if (varName == "CURRENT_FRAME")
- ss << mmd->time;
- else if (varName == "START_FRAME")
- ss << mmd->domain->cache_frame_start;
- else if (varName == "END_FRAME")
- ss << mmd->domain->cache_frame_end;
- else if (varName == "CACHE_DATA_FORMAT")
- ss << getCacheFileEnding(mmd->domain->cache_data_format);
- else if (varName == "CACHE_MESH_FORMAT")
- ss << getCacheFileEnding(mmd->domain->cache_mesh_format);
- else if (varName == "CACHE_NOISE_FORMAT")
- ss << getCacheFileEnding(mmd->domain->cache_noise_format);
- else if (varName == "CACHE_PARTICLE_FORMAT")
- ss << getCacheFileEnding(mmd->domain->cache_particle_format);
- else if (varName == "SIMULATION_METHOD") {
- if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_FLIP) {
- ss << "'FLIP'";
- }
- else if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_APIC) {
- ss << "'APIC'";
- }
- else {
- ss << "'NONE'";
- }
+ if (with_debug) {
+ cout << "Found variable " << varName << " with value " << it->second << endl;
}
- else if (varName == "FLIP_RATIO")
- ss << mmd->domain->flip_ratio;
- else if (varName == "PARTICLE_RANDOMNESS")
- ss << mmd->domain->particle_randomness;
- else if (varName == "PARTICLE_NUMBER")
- ss << mmd->domain->particle_number;
- else if (varName == "PARTICLE_MINIMUM")
- ss << mmd->domain->particle_minimum;
- else if (varName == "PARTICLE_MAXIMUM")
- ss << mmd->domain->particle_maximum;
- else if (varName == "PARTICLE_RADIUS")
- ss << mmd->domain->particle_radius;
- else if (varName == "FRACTIONS_THRESHOLD")
- ss << mmd->domain->fractions_threshold;
- else if (varName == "MESH_CONCAVE_UPPER")
- ss << mmd->domain->mesh_concave_upper;
- else if (varName == "MESH_CONCAVE_LOWER")
- ss << mmd->domain->mesh_concave_lower;
- else if (varName == "MESH_PARTICLE_RADIUS")
- ss << mmd->domain->mesh_particle_radius;
- else if (varName == "MESH_SMOOTHEN_POS")
- ss << mmd->domain->mesh_smoothen_pos;
- else if (varName == "MESH_SMOOTHEN_NEG")
- ss << mmd->domain->mesh_smoothen_neg;
- else if (varName == "USING_MESH")
- ss << (mmd->domain->flags & FLUID_DOMAIN_USE_MESH ? "True" : "False");
- else if (varName == "USING_IMPROVED_MESH")
- ss << (mmd->domain->mesh_generator == FLUID_DOMAIN_MESH_IMPROVED ? "True" : "False");
- else if (varName == "PARTICLE_BAND_WIDTH")
- ss << mmd->domain->particle_band_width;
- else if (varName == "SNDPARTICLE_TAU_MIN_WC")
- ss << mmd->domain->sndparticle_tau_min_wc;
- else if (varName == "SNDPARTICLE_TAU_MAX_WC")
- ss << mmd->domain->sndparticle_tau_max_wc;
- else if (varName == "SNDPARTICLE_TAU_MIN_TA")
- ss << mmd->domain->sndparticle_tau_min_ta;
- else if (varName == "SNDPARTICLE_TAU_MAX_TA")
- ss << mmd->domain->sndparticle_tau_max_ta;
- else if (varName == "SNDPARTICLE_TAU_MIN_K")
- ss << mmd->domain->sndparticle_tau_min_k;
- else if (varName == "SNDPARTICLE_TAU_MAX_K")
- ss << mmd->domain->sndparticle_tau_max_k;
- else if (varName == "SNDPARTICLE_K_WC")
- ss << mmd->domain->sndparticle_k_wc;
- else if (varName == "SNDPARTICLE_K_TA")
- ss << mmd->domain->sndparticle_k_ta;
- else if (varName == "SNDPARTICLE_K_B")
- ss << mmd->domain->sndparticle_k_b;
- else if (varName == "SNDPARTICLE_K_D")
- ss << mmd->domain->sndparticle_k_d;
- else if (varName == "SNDPARTICLE_L_MIN")
- ss << mmd->domain->sndparticle_l_min;
- else if (varName == "SNDPARTICLE_L_MAX")
- ss << mmd->domain->sndparticle_l_max;
- else if (varName == "SNDPARTICLE_BOUNDARY_DELETE")
- ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_DELETE);
- else if (varName == "SNDPARTICLE_BOUNDARY_PUSHOUT")
- ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_PUSHOUT);
- else if (varName == "SNDPARTICLE_POTENTIAL_RADIUS")
- ss << mmd->domain->sndparticle_potential_radius;
- else if (varName == "SNDPARTICLE_UPDATE_RADIUS")
- ss << mmd->domain->sndparticle_update_radius;
- else if (varName == "LIQUID_SURFACE_TENSION")
- ss << mmd->domain->surface_tension;
- else if (varName == "FLUID_VISCOSITY")
- ss << mmd->domain->viscosity_base * pow(10.0f, -mmd->domain->viscosity_exponent);
- else if (varName == "FLUID_DOMAIN_SIZE") {
- tmpFloat = MAX3(
- mmd->domain->global_size[0], mmd->domain->global_size[1], mmd->domain->global_size[2]);
- ss << tmpFloat;
- }
- else if (varName == "SNDPARTICLE_TYPES") {
- if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) {
- ss << "PtypeSpray";
- }
- if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) {
- if (!ss.str().empty())
- ss << "|";
- ss << "PtypeBubble";
- }
- if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) {
- if (!ss.str().empty())
- ss << "|";
- ss << "PtypeFoam";
- }
- if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) {
- if (!ss.str().empty())
- ss << "|";
- ss << "PtypeTracer";
- }
- if (ss.str().empty())
- ss << "0";
- }
- else if (varName == "USING_SNDPARTS") {
- tmpVar = (FLUID_DOMAIN_PARTICLE_SPRAY | FLUID_DOMAIN_PARTICLE_BUBBLE |
- FLUID_DOMAIN_PARTICLE_FOAM | FLUID_DOMAIN_PARTICLE_TRACER);
- ss << (((mmd->domain->particle_type & tmpVar)) ? "True" : "False");
- }
- else if (varName == "GUIDING_ALPHA")
- ss << mmd->domain->guide_alpha;
- else if (varName == "GUIDING_BETA")
- ss << mmd->domain->guide_beta;
- else if (varName == "GUIDING_FACTOR")
- ss << mmd->domain->guide_vel_factor;
- else if (varName == "GRAVITY_X")
- ss << mmd->domain->gravity[0];
- else if (varName == "GRAVITY_Y")
- ss << mmd->domain->gravity[1];
- else if (varName == "GRAVITY_Z")
- ss << mmd->domain->gravity[2];
- else if (varName == "CACHE_DIR")
- ss << mmd->domain->cache_directory;
- else if (varName == "CACHE_RESUMABLE")
- ss << (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL ? "False" : "True");
- else if (varName == "USING_ADAPTIVETIME")
- ss << (mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME ? "True" : "False");
- else if (varName == "USING_SPEEDVECTORS")
- ss << (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS ? "True" : "False");
- else if (varName == "USING_FRACTIONS")
- ss << (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS ? "True" : "False");
- else if (varName == "DELETE_IN_OBSTACLE")
- ss << (mmd->domain->flags & FLUID_DOMAIN_DELETE_IN_OBSTACLE ? "True" : "False");
- else if (varName == "USING_DIFFUSION")
- ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DIFFUSION ? "True" : "False");
- else
- std::cerr << "Fluid Error -- Unknown option: " << varName << std::endl;
- return ss.str();
-}
-
-std::string MANTA::parseLine(const std::string &line, FluidModifierData *mmd)
+
+ return it->second;
+}
+
+string MANTA::parseLine(const string &line)
{
if (line.size() == 0)
return "";
- std::string res = "";
+ string res = "";
int currPos = 0, start_del = 0, end_del = -1;
bool readingVar = false;
const char delimiter = '$';
@@ -1022,7 +864,7 @@ std::string MANTA::parseLine(const std::string &line, FluidModifierData *mmd)
else if (line[currPos] == delimiter && readingVar) {
readingVar = false;
end_del = currPos;
- res += getRealValue(line.substr(start_del, currPos - start_del), mmd);
+ res += getRealValue(line.substr(start_del, currPos - start_del));
}
currPos++;
}
@@ -1030,13 +872,21 @@ std::string MANTA::parseLine(const std::string &line, FluidModifierData *mmd)
return res;
}
-std::string MANTA::parseScript(const std::string &setup_string, FluidModifierData *mmd)
+string MANTA::parseScript(const string &setup_string, FluidModifierData *mmd)
{
- std::istringstream f(setup_string);
- std::ostringstream res;
- std::string line = "";
+ if (MANTA::with_debug)
+ cout << "MANTA::parseScript()" << endl;
+
+ istringstream f(setup_string);
+ ostringstream res;
+ string line = "";
+
+ // Update RNA map if modifier data is handed over
+ if (mmd) {
+ initializeRNAMap(mmd);
+ }
while (getline(f, line)) {
- res << parseLine(line, mmd) << "\n";
+ res << parseLine(line) << "\n";
}
return res.str();
}
@@ -1044,13 +894,14 @@ std::string MANTA::parseScript(const std::string &setup_string, FluidModifierDat
bool MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr)
{
if (MANTA::with_debug)
- std::cout << "MANTA::updateFlipStructures()" << std::endl;
+ cout << "MANTA::updateFlipStructures()" << endl;
+ FluidDomainSettings *mds = mmd->domain;
mFlipFromFile = false;
if (!mUsingLiquid)
return false;
- if (BLI_path_is_rel(mmd->domain->cache_directory))
+ if (BLI_path_is_rel(mds->cache_directory))
return false;
int result = 0;
@@ -1063,8 +914,8 @@ bool MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr)
mFlipParticleData->clear();
mFlipParticleVelocity->clear();
- std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
- std::string file = getFile(
+ string pformat = getCacheFileEnding(mds->cache_particle_format);
+ string file = getFile(
mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_PP, pformat.c_str(), framenr);
expected += 1;
@@ -1086,13 +937,14 @@ bool MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr)
bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr)
{
if (MANTA::with_debug)
- std::cout << "MANTA::updateMeshStructures()" << std::endl;
+ cout << "MANTA::updateMeshStructures()" << endl;
+ FluidDomainSettings *mds = mmd->domain;
mMeshFromFile = false;
if (!mUsingMesh)
return false;
- if (BLI_path_is_rel(mmd->domain->cache_directory))
+ if (BLI_path_is_rel(mds->cache_directory))
return false;
int result = 0;
@@ -1108,9 +960,9 @@ bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr)
if (mMeshVelocities)
mMeshVelocities->clear();
- std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format);
- std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
- std::string file = getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_DOMAIN_FILE_MESH, mformat, framenr);
+ string mformat = getCacheFileEnding(mds->cache_mesh_format);
+ string dformat = getCacheFileEnding(mds->cache_data_format);
+ string file = getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_DOMAIN_FILE_MESH, mformat, framenr);
expected += 1;
if (BLI_exists(file.c_str())) {
@@ -1133,13 +985,14 @@ bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr)
bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr)
{
if (MANTA::with_debug)
- std::cout << "MANTA::updateParticleStructures()" << std::endl;
+ cout << "MANTA::updateParticleStructures()" << endl;
+ FluidDomainSettings *mds = mmd->domain;
mParticlesFromFile = false;
if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers)
return false;
- if (BLI_path_is_rel(mmd->domain->cache_directory))
+ if (BLI_path_is_rel(mds->cache_directory))
return false;
int result = 0;
@@ -1153,8 +1006,8 @@ bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr)
mSndParticleVelocity->clear();
mSndParticleLife->clear();
- std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
- std::string file = getFile(
+ string pformat = getCacheFileEnding(mds->cache_particle_format);
+ string file = getFile(
mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_DOMAIN_FILE_PPSND, pformat, framenr);
expected += 1;
@@ -1183,21 +1036,21 @@ bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr)
bool MANTA::updateSmokeStructures(FluidModifierData *mmd, int framenr)
{
if (MANTA::with_debug)
- std::cout << "MANTA::updateGridStructures()" << std::endl;
+ cout << "MANTA::updateGridStructures()" << endl;
+ FluidDomainSettings *mds = mmd->domain;
mSmokeFromFile = false;
if (!mUsingSmoke)
return false;
- if (BLI_path_is_rel(mmd->domain->cache_directory))
+ if (BLI_path_is_rel(mds->cache_directory))
return false;
int result = 0;
int expected = 0; /* Expected number of read successes for this frame. */
- std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
- std::string file = getFile(
- mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_DENSITY, dformat, framenr);
+ string dformat = getCacheFileEnding(mds->cache_data_format);
+ string file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_DENSITY, dformat, framenr);
expected += 1;
if (BLI_exists(file.c_str())) {
@@ -1273,21 +1126,22 @@ bool MANTA::updateSmokeStructures(FluidModifierData *mmd, int framenr)
bool MANTA::updateNoiseStructures(FluidModifierData *mmd, int framenr)
{
if (MANTA::with_debug)
- std::cout << "MANTA::updateNoiseStructures()" << std::endl;
+ cout << "MANTA::updateNoiseStructures()" << endl;
+ FluidDomainSettings *mds = mmd->domain;
mNoiseFromFile = false;
if (!mUsingSmoke || !mUsingNoise)
return false;
- if (BLI_path_is_rel(mmd->domain->cache_directory))
+ if (BLI_path_is_rel(mds->cache_directory))
return false;
int result = 0;
int expected = 0; /* Expected number of read successes for this frame. */
- std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
- std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format);
- std::string file = getFile(
+ string dformat = getCacheFileEnding(mds->cache_data_format);
+ string nformat = getCacheFileEnding(mds->cache_noise_format);
+ string file = getFile(
mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_DENSITYNOISE, nformat, framenr);
expected += 1;
@@ -1353,10 +1207,10 @@ bool MANTA::updateNoiseStructures(FluidModifierData *mmd, int framenr)
}
/* Dirty hack: Needed to format paths from python code that is run via PyRun_SimpleString */
-static std::string escapeSlashes(std::string const &s)
+static string escapeSlashes(string const &s)
{
- std::string result = "";
- for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i) {
+ string result = "";
+ for (string::const_iterator i = s.begin(), end = s.end(); i != end; ++i) {
unsigned char c = *i;
if (c == '\\')
result += "\\\\";
@@ -1369,21 +1223,20 @@ static std::string escapeSlashes(std::string const &s)
bool MANTA::writeConfiguration(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::writeConfiguration()" << std::endl;
+ cout << "MANTA::writeConfiguration()" << endl;
FluidDomainSettings *mds = mmd->domain;
- std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_CONFIG);
- std::string format = FLUID_DOMAIN_EXTENSION_UNI;
- std::string file = getFile(
- mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, format, framenr);
+ string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_CONFIG);
+ string format = FLUID_DOMAIN_EXTENSION_UNI;
+ string file = getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, format, framenr);
/* Create 'config' subdir if it does not exist already. */
BLI_dir_create_recursive(directory.c_str());
gzFile gzf = (gzFile)BLI_gzopen(file.c_str(), "wb1"); // do some compression
if (!gzf) {
- std::cerr << "Fluid Error -- Cannot open file " << file << std::endl;
+ cerr << "Fluid Error -- Cannot open file " << file << endl;
return false;
}
@@ -1408,17 +1261,18 @@ bool MANTA::writeConfiguration(FluidModifierData *mmd, int framenr)
bool MANTA::writeData(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::writeData()" << std::endl;
+ cout << "MANTA::writeData()" << endl;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
- std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_DATA);
- std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
- std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_DATA);
+ string dformat = getCacheFileEnding(mds->cache_data_format);
+ string pformat = getCacheFileEnding(mds->cache_particle_format);
- bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL);
- std::string resumable_cache = (final_cache) ? "False" : "True";
+ bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL);
+ string resumable_cache = (final_cache) ? "False" : "True";
ss.str("");
ss << "fluid_save_data_" << mCurrentID << "('" << escapeSlashes(directory) << "', " << framenr
@@ -1443,16 +1297,17 @@ bool MANTA::writeData(FluidModifierData *mmd, int framenr)
bool MANTA::writeNoise(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::writeNoise()" << std::endl;
+ cout << "MANTA::writeNoise()" << endl;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
- std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE);
- std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format);
+ string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE);
+ string nformat = getCacheFileEnding(mds->cache_noise_format);
- bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL);
- std::string resumable_cache = (final_cache) ? "False" : "True";
+ bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL);
+ string resumable_cache = (final_cache) ? "False" : "True";
if (mUsingSmoke && mUsingNoise) {
ss.str("");
@@ -1466,22 +1321,21 @@ bool MANTA::writeNoise(FluidModifierData *mmd, int framenr)
bool MANTA::readConfiguration(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::readConfiguration()" << std::endl;
+ cout << "MANTA::readConfiguration()" << endl;
FluidDomainSettings *mds = mmd->domain;
float dummy;
- std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_CONFIG);
- std::string format = FLUID_DOMAIN_EXTENSION_UNI;
- std::string file = getFile(
- mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, format, framenr);
+ string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_CONFIG);
+ string format = FLUID_DOMAIN_EXTENSION_UNI;
+ string file = getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, format, framenr);
if (!hasConfig(mmd, framenr))
return false;
gzFile gzf = (gzFile)BLI_gzopen(file.c_str(), "rb"); // do some compression
if (!gzf) {
- std::cerr << "Fluid Error -- Cannot open file " << file << std::endl;
+ cerr << "Fluid Error -- Cannot open file " << file << endl;
return false;
}
@@ -1507,21 +1361,22 @@ bool MANTA::readConfiguration(FluidModifierData *mmd, int framenr)
bool MANTA::readData(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::readData()" << std::endl;
+ cout << "MANTA::readData()" << endl;
if (!mUsingSmoke && !mUsingLiquid)
return false;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
bool result = true;
- std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_DATA);
- std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
- std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_DATA);
+ string dformat = getCacheFileEnding(mds->cache_data_format);
+ string pformat = getCacheFileEnding(mds->cache_particle_format);
- bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL);
- std::string resumable_cache = (final_cache) ? "False" : "True";
+ bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL);
+ string resumable_cache = (final_cache) ? "False" : "True";
/* Sanity check: Are cache files present? */
if (!hasData(mmd, framenr))
@@ -1552,19 +1407,20 @@ bool MANTA::readData(FluidModifierData *mmd, int framenr)
bool MANTA::readNoise(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::readNoise()" << std::endl;
+ cout << "MANTA::readNoise()" << endl;
if (!mUsingSmoke || !mUsingNoise)
return false;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
- std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE);
- std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format);
+ string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE);
+ string nformat = getCacheFileEnding(mds->cache_noise_format);
- bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL);
- std::string resumable_cache = (final_cache) ? "False" : "True";
+ bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL);
+ string resumable_cache = (final_cache) ? "False" : "True";
/* Sanity check: Are cache files present? */
if (!hasNoise(mmd, framenr))
@@ -1584,17 +1440,18 @@ bool MANTA::readNoise(FluidModifierData *mmd, int framenr)
bool MANTA::readMesh(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::readMesh()" << std::endl;
+ cout << "MANTA::readMesh()" << endl;
if (!mUsingLiquid || !mUsingMesh)
return false;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
- std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_MESH);
- std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format);
- std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_MESH);
+ string mformat = getCacheFileEnding(mds->cache_mesh_format);
+ string dformat = getCacheFileEnding(mds->cache_data_format);
/* Sanity check: Are cache files present? */
if (!hasMesh(mmd, framenr))
@@ -1621,21 +1478,22 @@ bool MANTA::readMesh(FluidModifierData *mmd, int framenr)
bool MANTA::readParticles(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::readParticles()" << std::endl;
+ cout << "MANTA::readParticles()" << endl;
if (!mUsingLiquid)
return false;
if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers)
return false;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
- std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_PARTICLES);
- std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_PARTICLES);
+ string pformat = getCacheFileEnding(mds->cache_particle_format);
- bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL);
- std::string resumable_cache = (final_cache) ? "False" : "True";
+ bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL);
+ string resumable_cache = (final_cache) ? "False" : "True";
/* Sanity check: Are cache files present? */
if (!hasParticles(mmd, framenr))
@@ -1652,19 +1510,21 @@ bool MANTA::readParticles(FluidModifierData *mmd, int framenr)
bool MANTA::readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain)
{
if (with_debug)
- std::cout << "MANTA::readGuiding()" << std::endl;
+ cout << "MANTA::readGuiding()" << endl;
+
+ FluidDomainSettings *mds = mmd->domain;
if (!mUsingGuiding)
return false;
- if (!mmd->domain)
+ if (!mds)
return false;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
- std::string directory = (sourceDomain) ? getDirectory(mmd, FLUID_DOMAIN_DIR_DATA) :
- getDirectory(mmd, FLUID_DOMAIN_DIR_GUIDE);
- std::string gformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ string directory = (sourceDomain) ? getDirectory(mmd, FLUID_DOMAIN_DIR_DATA) :
+ getDirectory(mmd, FLUID_DOMAIN_DIR_GUIDE);
+ string gformat = getCacheFileEnding(mds->cache_data_format);
/* Sanity check: Are cache files present? */
if (!hasGuiding(mmd, framenr, sourceDomain))
@@ -1688,28 +1548,26 @@ bool MANTA::readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain)
bool MANTA::bakeData(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::bakeData()" << std::endl;
+ cout << "MANTA::bakeData()" << endl;
- std::string tmpString, finalString;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ string tmpString, finalString;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
char cacheDirData[FILE_MAX], cacheDirGuiding[FILE_MAX];
cacheDirData[0] = '\0';
cacheDirGuiding[0] = '\0';
- std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
- std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
- std::string gformat = dformat; // Use same data format for guiding format
+ string dformat = getCacheFileEnding(mds->cache_data_format);
+ string pformat = getCacheFileEnding(mds->cache_particle_format);
+ string gformat = dformat; // Use same data format for guiding format
- BLI_path_join(cacheDirData,
- sizeof(cacheDirData),
- mmd->domain->cache_directory,
- FLUID_DOMAIN_DIR_DATA,
- nullptr);
+ BLI_path_join(
+ cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr);
BLI_path_join(cacheDirGuiding,
sizeof(cacheDirGuiding),
- mmd->domain->cache_directory,
+ mds->cache_directory,
FLUID_DOMAIN_DIR_GUIDE,
nullptr);
BLI_path_make_safe(cacheDirData);
@@ -1727,31 +1585,26 @@ bool MANTA::bakeData(FluidModifierData *mmd, int framenr)
bool MANTA::bakeNoise(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::bakeNoise()" << std::endl;
+ cout << "MANTA::bakeNoise()" << endl;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
char cacheDirData[FILE_MAX], cacheDirNoise[FILE_MAX];
cacheDirData[0] = '\0';
cacheDirNoise[0] = '\0';
- std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
- std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format);
+ string dformat = getCacheFileEnding(mds->cache_data_format);
+ string nformat = getCacheFileEnding(mds->cache_noise_format);
- bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL);
- std::string resumable_cache = (final_cache) ? "False" : "True";
+ bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL);
+ string resumable_cache = (final_cache) ? "False" : "True";
- BLI_path_join(cacheDirData,
- sizeof(cacheDirData),
- mmd->domain->cache_directory,
- FLUID_DOMAIN_DIR_DATA,
- nullptr);
- BLI_path_join(cacheDirNoise,
- sizeof(cacheDirNoise),
- mmd->domain->cache_directory,
- FLUID_DOMAIN_DIR_NOISE,
- nullptr);
+ BLI_path_join(
+ cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr);
+ BLI_path_join(
+ cacheDirNoise, sizeof(cacheDirNoise), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, nullptr);
BLI_path_make_safe(cacheDirData);
BLI_path_make_safe(cacheDirNoise);
@@ -1767,29 +1620,24 @@ bool MANTA::bakeNoise(FluidModifierData *mmd, int framenr)
bool MANTA::bakeMesh(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::bakeMesh()" << std::endl;
+ cout << "MANTA::bakeMesh()" << endl;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
char cacheDirData[FILE_MAX], cacheDirMesh[FILE_MAX];
cacheDirData[0] = '\0';
cacheDirMesh[0] = '\0';
- std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
- std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format);
- std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ string dformat = getCacheFileEnding(mds->cache_data_format);
+ string mformat = getCacheFileEnding(mds->cache_mesh_format);
+ string pformat = getCacheFileEnding(mds->cache_particle_format);
- BLI_path_join(cacheDirData,
- sizeof(cacheDirData),
- mmd->domain->cache_directory,
- FLUID_DOMAIN_DIR_DATA,
- nullptr);
- BLI_path_join(cacheDirMesh,
- sizeof(cacheDirMesh),
- mmd->domain->cache_directory,
- FLUID_DOMAIN_DIR_MESH,
- nullptr);
+ BLI_path_join(
+ cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr);
+ BLI_path_join(
+ cacheDirMesh, sizeof(cacheDirMesh), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, nullptr);
BLI_path_make_safe(cacheDirData);
BLI_path_make_safe(cacheDirMesh);
@@ -1805,29 +1653,27 @@ bool MANTA::bakeMesh(FluidModifierData *mmd, int framenr)
bool MANTA::bakeParticles(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::bakeParticles()" << std::endl;
+ cout << "MANTA::bakeParticles()" << endl;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
char cacheDirData[FILE_MAX], cacheDirParticles[FILE_MAX];
cacheDirData[0] = '\0';
cacheDirParticles[0] = '\0';
- std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
- std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ string dformat = getCacheFileEnding(mds->cache_data_format);
+ string pformat = getCacheFileEnding(mds->cache_particle_format);
- bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL);
- std::string resumable_cache = (final_cache) ? "False" : "True";
+ bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL);
+ string resumable_cache = (final_cache) ? "False" : "True";
- BLI_path_join(cacheDirData,
- sizeof(cacheDirData),
- mmd->domain->cache_directory,
- FLUID_DOMAIN_DIR_DATA,
- nullptr);
+ BLI_path_join(
+ cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr);
BLI_path_join(cacheDirParticles,
sizeof(cacheDirParticles),
- mmd->domain->cache_directory,
+ mds->cache_directory,
FLUID_DOMAIN_DIR_PARTICLES,
nullptr);
BLI_path_make_safe(cacheDirData);
@@ -1845,22 +1691,23 @@ bool MANTA::bakeParticles(FluidModifierData *mmd, int framenr)
bool MANTA::bakeGuiding(FluidModifierData *mmd, int framenr)
{
if (with_debug)
- std::cout << "MANTA::bakeGuiding()" << std::endl;
+ cout << "MANTA::bakeGuiding()" << endl;
- std::ostringstream ss;
- std::vector<std::string> pythonCommands;
+ ostringstream ss;
+ vector<string> pythonCommands;
+ FluidDomainSettings *mds = mmd->domain;
char cacheDirGuiding[FILE_MAX];
cacheDirGuiding[0] = '\0';
- std::string gformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ string gformat = getCacheFileEnding(mds->cache_data_format);
- bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL);
- std::string resumable_cache = (final_cache) ? "False" : "True";
+ bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL);
+ string resumable_cache = (final_cache) ? "False" : "True";
BLI_path_join(cacheDirGuiding,
sizeof(cacheDirGuiding),
- mmd->domain->cache_directory,
+ mds->cache_directory,
FLUID_DOMAIN_DIR_GUIDE,
nullptr);
BLI_path_make_safe(cacheDirGuiding);
@@ -1875,8 +1722,8 @@ bool MANTA::bakeGuiding(FluidModifierData *mmd, int framenr)
bool MANTA::updateVariables(FluidModifierData *mmd)
{
- std::string tmpString, finalString;
- std::vector<std::string> pythonCommands;
+ string tmpString, finalString;
+ vector<string> pythonCommands;
tmpString += fluid_variables;
if (mUsingSmoke)
@@ -1906,13 +1753,15 @@ bool MANTA::updateVariables(FluidModifierData *mmd)
void MANTA::exportSmokeScript(FluidModifierData *mmd)
{
if (with_debug)
- std::cout << "MANTA::exportSmokeScript()" << std::endl;
+ cout << "MANTA::exportSmokeScript()" << endl;
char cacheDir[FILE_MAX] = "\0";
char cacheDirScript[FILE_MAX] = "\0";
+ FluidDomainSettings *mds = mmd->domain;
+
BLI_path_join(
- cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, nullptr);
+ cacheDir, sizeof(cacheDir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, nullptr);
BLI_path_make_safe(cacheDir);
/* Create 'script' subdir if it does not exist already */
BLI_dir_create_recursive(cacheDir);
@@ -1920,16 +1769,16 @@ void MANTA::exportSmokeScript(FluidModifierData *mmd)
cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_SMOKE_SCRIPT, nullptr);
BLI_path_make_safe(cacheDir);
- bool noise = mmd->domain->flags & FLUID_DOMAIN_USE_NOISE;
- bool heat = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT;
- bool colors = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS;
- bool fire = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE;
- bool obstacle = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
- bool guiding = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE;
- bool invel = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
- bool outflow = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW;
+ bool noise = mds->flags & FLUID_DOMAIN_USE_NOISE;
+ bool heat = mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT;
+ bool colors = mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS;
+ bool fire = mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE;
+ bool obstacle = mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
+ bool guiding = mds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE;
+ bool invel = mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
+ bool outflow = mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW;
- std::string manta_script;
+ string manta_script;
// Libraries
manta_script += header_libraries + manta_import;
@@ -2001,10 +1850,10 @@ void MANTA::exportSmokeScript(FluidModifierData *mmd)
manta_script += header_main + smoke_standalone + fluid_standalone;
// Fill in missing variables in script
- std::string final_script = MANTA::parseScript(manta_script, mmd);
+ string final_script = MANTA::parseScript(manta_script, mmd);
// Write script
- std::ofstream myfile;
+ ofstream myfile;
myfile.open(cacheDirScript);
myfile << final_script;
myfile.close();
@@ -2013,13 +1862,15 @@ void MANTA::exportSmokeScript(FluidModifierData *mmd)
void MANTA::exportLiquidScript(FluidModifierData *mmd)
{
if (with_debug)
- std::cout << "MANTA::exportLiquidScript()" << std::endl;
+ cout << "MANTA::exportLiquidScript()" << endl;
char cacheDir[FILE_MAX] = "\0";
char cacheDirScript[FILE_MAX] = "\0";
+ FluidDomainSettings *mds = mmd->domain;
+
BLI_path_join(
- cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, nullptr);
+ cacheDir, sizeof(cacheDir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, nullptr);
BLI_path_make_safe(cacheDir);
/* Create 'script' subdir if it does not exist already */
BLI_dir_create_recursive(cacheDir);
@@ -2027,18 +1878,18 @@ void MANTA::exportLiquidScript(FluidModifierData *mmd)
cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_LIQUID_SCRIPT, nullptr);
BLI_path_make_safe(cacheDirScript);
- bool mesh = mmd->domain->flags & FLUID_DOMAIN_USE_MESH;
- bool drops = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY;
- bool bubble = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE;
- bool floater = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
- bool tracer = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER;
- bool obstacle = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
- bool fractions = mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS;
- bool guiding = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE;
- bool invel = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
- bool outflow = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW;
+ bool mesh = mds->flags & FLUID_DOMAIN_USE_MESH;
+ bool drops = mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY;
+ bool bubble = mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE;
+ bool floater = mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
+ bool tracer = mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER;
+ bool obstacle = mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
+ bool fractions = mds->flags & FLUID_DOMAIN_USE_FRACTIONS;
+ bool guiding = mds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE;
+ bool invel = mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
+ bool outflow = mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW;
- std::string manta_script;
+ string manta_script;
// Libraries
manta_script += header_libraries + manta_import;
@@ -2108,10 +1959,10 @@ void MANTA::exportLiquidScript(FluidModifierData *mmd)
manta_script += header_main + liquid_standalone + fluid_standalone;
// Fill in missing variables in script
- std::string final_script = MANTA::parseScript(manta_script, mmd);
+ string final_script = MANTA::parseScript(manta_script, mmd);
// Write script
- std::ofstream myfile;
+ ofstream myfile;
myfile.open(cacheDirScript);
myfile << final_script;
myfile.close();
@@ -2124,14 +1975,12 @@ void MANTA::exportLiquidScript(FluidModifierData *mmd)
*
* Important! Return value: New reference or nullptr
* Caller of this function needs to handle reference count of returned object. */
-static PyObject *callPythonFunction(std::string varName,
- std::string functionName,
- bool isAttribute = false)
+static PyObject *callPythonFunction(string varName, string functionName, bool isAttribute = false)
{
if ((varName == "") || (functionName == "")) {
if (MANTA::with_debug)
- std::cout << "Missing Python variable name and/or function name -- name is: " << varName
- << ", function name is: " << functionName << std::endl;
+ cout << "Missing Python variable name and/or function name -- name is: " << varName
+ << ", function name is: " << functionName << endl;
return nullptr;
}
@@ -2185,8 +2034,8 @@ static void *pyObjectToPointer(PyObject *inputObject)
Py_DECREF(inputObject);
- std::string str(result);
- std::istringstream in(str);
+ string str(result);
+ istringstream in(str);
void *dataPointer = nullptr;
in >> dataPointer;
@@ -2233,11 +2082,11 @@ static long pyObjectToLong(PyObject *inputObject)
int MANTA::getFrame()
{
if (with_debug)
- std::cout << "MANTA::getFrame()" << std::endl;
+ cout << "MANTA::getFrame()" << endl;
- std::string func = "frame";
- std::string id = std::to_string(mCurrentID);
- std::string solver = "s" + id;
+ string func = "frame";
+ string id = to_string(mCurrentID);
+ string solver = "s" + id;
return pyObjectToLong(callPythonFunction(solver, func, true));
}
@@ -2245,11 +2094,11 @@ int MANTA::getFrame()
float MANTA::getTimestep()
{
if (with_debug)
- std::cout << "MANTA::getTimestep()" << std::endl;
+ cout << "MANTA::getTimestep()" << endl;
- std::string func = "timestep";
- std::string id = std::to_string(mCurrentID);
- std::string solver = "s" + id;
+ string func = "timestep";
+ string id = to_string(mCurrentID);
+ string solver = "s" + id;
return (float)pyObjectToDouble(callPythonFunction(solver, func, true));
}
@@ -2263,10 +2112,10 @@ bool MANTA::needsRealloc(FluidModifierData *mmd)
void MANTA::adaptTimestep()
{
if (with_debug)
- std::cout << "MANTA::adaptTimestep()" << std::endl;
+ cout << "MANTA::adaptTimestep()" << endl;
- std::vector<std::string> pythonCommands;
- std::ostringstream ss;
+ vector<string> pythonCommands;
+ ostringstream ss;
ss << "fluid_adapt_time_step_" << mCurrentID << "()";
pythonCommands.push_back(ss.str());
@@ -2274,14 +2123,14 @@ void MANTA::adaptTimestep()
runPythonString(pythonCommands);
}
-bool MANTA::updateMeshFromFile(std::string filename)
+bool MANTA::updateMeshFromFile(string filename)
{
- std::string fname(filename);
- std::string::size_type idx;
+ string fname(filename);
+ string::size_type idx;
idx = fname.rfind('.');
- if (idx != std::string::npos) {
- std::string extension = fname.substr(idx + 1);
+ if (idx != string::npos) {
+ string extension = fname.substr(idx + 1);
if (extension.compare("gz") == 0)
return updateMeshFromBobj(filename);
@@ -2290,27 +2139,25 @@ bool MANTA::updateMeshFromFile(std::string filename)
else if (extension.compare("uni") == 0)
return updateMeshFromUni(filename);
else
- std::cerr << "Fluid Error -- updateMeshFromFile(): Invalid file extension in file: "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateMeshFromFile(): Invalid file extension in file: " << filename
+ << endl;
}
else {
- std::cerr << "Fluid Error -- updateMeshFromFile(): Unable to open file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateMeshFromFile(): Unable to open file: " << filename << endl;
}
return false;
}
-bool MANTA::updateMeshFromBobj(std::string filename)
+bool MANTA::updateMeshFromBobj(string filename)
{
if (with_debug)
- std::cout << "MANTA::updateMeshFromBobj()" << std::endl;
+ cout << "MANTA::updateMeshFromBobj()" << endl;
gzFile gzf;
gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb1"); // do some compression
if (!gzf) {
- std::cerr << "Fluid Error -- updateMeshFromBobj(): Unable to open file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateMeshFromBobj(): Unable to open file: " << filename << endl;
return false;
}
@@ -2319,15 +2166,14 @@ bool MANTA::updateMeshFromBobj(std::string filename)
// Num vertices
readBytes = gzread(gzf, &numBuffer, sizeof(int));
if (!readBytes) {
- std::cerr
- << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh vertices from "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh vertices from "
+ << filename << endl;
gzclose(gzf);
return false;
}
if (with_debug)
- std::cout << "read mesh , num verts: " << numBuffer << " , in file: " << filename << std::endl;
+ cout << "read mesh , num verts: " << numBuffer << " , in file: " << filename << endl;
int numChunks = (int)(ceil((float)numBuffer / NODE_CHUNK));
int readLen, readStart, readEnd, k;
@@ -2348,8 +2194,8 @@ bool MANTA::updateMeshFromBobj(std::string filename)
readBytes = gzread(gzf, bufferVerts, readLen * sizeof(float) * 3);
if (!readBytes) {
- std::cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh vertices from "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh vertices from "
+ << filename << endl;
MEM_freeN(bufferVerts);
gzclose(gzf);
return false;
@@ -2361,7 +2207,7 @@ bool MANTA::updateMeshFromBobj(std::string filename)
CLAMP(readEnd, 0, numBuffer);
k = 0;
- for (std::vector<MANTA::Node>::size_type j = readStart; j < readEnd; j++, k += 3) {
+ for (vector<MANTA::Node>::size_type j = readStart; j < readEnd; j++, k += 3) {
mMeshNodes->at(j).pos[0] = bufferVerts[k];
mMeshNodes->at(j).pos[1] = bufferVerts[k + 1];
mMeshNodes->at(j).pos[2] = bufferVerts[k + 2];
@@ -2374,15 +2220,14 @@ bool MANTA::updateMeshFromBobj(std::string filename)
// Num normals
readBytes = gzread(gzf, &numBuffer, sizeof(int));
if (!readBytes) {
- std::cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh normals from "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh normals from "
+ << filename << endl;
gzclose(gzf);
return false;
}
if (with_debug)
- std::cout << "read mesh , num normals : " << numBuffer << " , in file: " << filename
- << std::endl;
+ cout << "read mesh , num normals : " << numBuffer << " , in file: " << filename << endl;
if (numBuffer) {
// Normals
@@ -2401,8 +2246,8 @@ bool MANTA::updateMeshFromBobj(std::string filename)
readBytes = gzread(gzf, bufferNormals, readLen * sizeof(float) * 3);
if (!readBytes) {
- std::cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh normals from "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh normals from "
+ << filename << endl;
MEM_freeN(bufferNormals);
gzclose(gzf);
return false;
@@ -2414,7 +2259,7 @@ bool MANTA::updateMeshFromBobj(std::string filename)
CLAMP(readEnd, 0, numBuffer);
k = 0;
- for (std::vector<MANTA::Node>::size_type j = readStart; j < readEnd; j++, k += 3) {
+ for (vector<MANTA::Node>::size_type j = readStart; j < readEnd; j++, k += 3) {
mMeshNodes->at(j).normal[0] = bufferNormals[k];
mMeshNodes->at(j).normal[1] = bufferNormals[k + 1];
mMeshNodes->at(j).normal[2] = bufferNormals[k + 2];
@@ -2427,16 +2272,15 @@ bool MANTA::updateMeshFromBobj(std::string filename)
// Num triangles
readBytes = gzread(gzf, &numBuffer, sizeof(int));
if (!readBytes) {
- std::cerr
- << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh triangles from "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh triangles from "
+ << filename << endl;
gzclose(gzf);
return false;
}
if (with_debug)
- std::cout << "Fluid: Read mesh , num triangles : " << numBuffer << " , in file: " << filename
- << std::endl;
+ cout << "Fluid: Read mesh , num triangles : " << numBuffer << " , in file: " << filename
+ << endl;
numChunks = (int)(ceil((float)numBuffer / TRIANGLE_CHUNK));
@@ -2456,8 +2300,8 @@ bool MANTA::updateMeshFromBobj(std::string filename)
readBytes = gzread(gzf, bufferTriangles, readLen * sizeof(int) * 3);
if (!readBytes) {
- std::cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh triangles from "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh triangles from "
+ << filename << endl;
MEM_freeN(bufferTriangles);
gzclose(gzf);
return false;
@@ -2469,7 +2313,7 @@ bool MANTA::updateMeshFromBobj(std::string filename)
CLAMP(readEnd, 0, numBuffer);
k = 0;
- for (std::vector<MANTA::Triangle>::size_type j = readStart; j < readEnd; j++, k += 3) {
+ for (vector<MANTA::Triangle>::size_type j = readStart; j < readEnd; j++, k += 3) {
mMeshTriangles->at(j).c[0] = bufferTriangles[k];
mMeshTriangles->at(j).c[1] = bufferTriangles[k + 1];
mMeshTriangles->at(j).c[2] = bufferTriangles[k + 2];
@@ -2481,24 +2325,23 @@ bool MANTA::updateMeshFromBobj(std::string filename)
return (gzclose(gzf) == Z_OK);
}
-bool MANTA::updateMeshFromObj(std::string filename)
+bool MANTA::updateMeshFromObj(string filename)
{
if (with_debug)
- std::cout << "MANTA::updateMeshFromObj()" << std::endl;
+ cout << "MANTA::updateMeshFromObj()" << endl;
- std::ifstream ifs(filename);
+ ifstream ifs(filename);
float fbuffer[3];
int ibuffer[3];
int cntVerts = 0, cntNormals = 0, cntTris = 0;
if (!ifs.good()) {
- std::cerr << "Fluid Error -- updateMeshFromObj(): Unable to open file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateMeshFromObj(): Unable to open file: " << filename << endl;
return false;
}
while (ifs.good() && !ifs.eof()) {
- std::string id;
+ string id;
ifs >> id;
if (id[0] == '#') {
@@ -2512,8 +2355,8 @@ bool MANTA::updateMeshFromObj(std::string filename)
else if (id == "vn") {
// normals
if (getNumVertices() != cntVerts) {
- std::cerr << "Fluid Error -- updateMeshFromObj(): Invalid number of mesh nodes in file: "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateMeshFromObj(): Invalid number of mesh nodes in file: "
+ << filename << endl;
return false;
}
@@ -2536,20 +2379,20 @@ bool MANTA::updateMeshFromObj(std::string filename)
}
else if (id == "g") {
// group
- std::string group;
+ string group;
ifs >> group;
}
else if (id == "f") {
// face
- std::string face;
+ string face;
for (int i = 0; i < 3; i++) {
ifs >> face;
- if (face.find('/') != std::string::npos)
+ if (face.find('/') != string::npos)
face = face.substr(0, face.find('/')); // ignore other indices
int idx = atoi(face.c_str()) - 1;
if (idx < 0) {
- std::cerr << "Fluid Error -- updateMeshFromObj(): Invalid face encountered in file: "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateMeshFromObj(): Invalid face encountered in file: "
+ << filename << endl;
return false;
}
ibuffer[i] = idx;
@@ -2571,10 +2414,10 @@ bool MANTA::updateMeshFromObj(std::string filename)
return true;
}
-bool MANTA::updateMeshFromUni(std::string filename)
+bool MANTA::updateMeshFromUni(string filename)
{
if (with_debug)
- std::cout << "MANTA::updateMeshFromUni()" << std::endl;
+ cout << "MANTA::updateMeshFromUni()" << endl;
gzFile gzf;
float fbuffer[4];
@@ -2582,8 +2425,7 @@ bool MANTA::updateMeshFromUni(std::string filename)
gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb1"); // do some compression
if (!gzf) {
- std::cerr << "Fluid Error -- updateMeshFromUni(): Unable to open file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateMeshFromUni(): Unable to open file: " << filename << endl;
return false;
}
@@ -2591,13 +2433,13 @@ bool MANTA::updateMeshFromUni(std::string filename)
char file_magic[5] = {0, 0, 0, 0, 0};
readBytes = gzread(gzf, file_magic, 4);
if (!readBytes) {
- std::cerr << "Fluid Error -- updateMeshFromUni(): Unable to read header in file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateMeshFromUni(): Unable to read header in file: " << filename
+ << endl;
gzclose(gzf);
return false;
}
- std::vector<pVel> *velocityPointer = mMeshVelocities;
+ vector<pVel> *velocityPointer = mMeshVelocities;
// mdata uni header
const int STR_LEN_PDATA = 256;
@@ -2613,19 +2455,18 @@ bool MANTA::updateMeshFromUni(std::string filename)
gzread(gzf, &timestamp, sizeof(unsigned long long));
if (with_debug)
- std::cout << "Fluid: Read " << ibuffer[0] << " vertices in file: " << filename << std::endl;
+ cout << "Fluid: Read " << ibuffer[0] << " vertices in file: " << filename << endl;
// Sanity checks
const int meshSize = sizeof(float) * 3 + sizeof(int);
if (!(bytesPerElement == meshSize) && (elementType == 0)) {
- std::cerr << "Fluid Error -- updateMeshFromUni(): Invalid header in file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateMeshFromUni(): Invalid header in file: " << filename << endl;
gzclose(gzf);
return false;
}
if (!ibuffer[0]) { // Any vertices present?
- std::cerr << "Fluid Error -- updateMeshFromUni(): No vertices present in file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateMeshFromUni(): No vertices present in file: " << filename
+ << endl;
gzclose(gzf);
return false;
}
@@ -2640,7 +2481,7 @@ bool MANTA::updateMeshFromUni(std::string filename)
velocityPointer->resize(numParticles);
MANTA::pVel *bufferPVel;
- for (std::vector<pVel>::iterator it = velocityPointer->begin(); it != velocityPointer->end();
+ for (vector<pVel>::iterator it = velocityPointer->begin(); it != velocityPointer->end();
++it) {
gzread(gzf, fbuffer, sizeof(float) * 3);
bufferPVel = (MANTA::pVel *)fbuffer;
@@ -2652,44 +2493,42 @@ bool MANTA::updateMeshFromUni(std::string filename)
return (gzclose(gzf) == Z_OK);
}
-bool MANTA::updateParticlesFromFile(std::string filename, bool isSecondarySys, bool isVelData)
+bool MANTA::updateParticlesFromFile(string filename, bool isSecondarySys, bool isVelData)
{
if (with_debug)
- std::cout << "MANTA::updateParticlesFromFile()" << std::endl;
+ cout << "MANTA::updateParticlesFromFile()" << endl;
- std::string fname(filename);
- std::string::size_type idx;
+ string fname(filename);
+ string::size_type idx;
idx = fname.rfind('.');
- if (idx != std::string::npos) {
- std::string extension = fname.substr(idx + 1);
+ if (idx != string::npos) {
+ string extension = fname.substr(idx + 1);
if (extension.compare("uni") == 0)
return updateParticlesFromUni(filename, isSecondarySys, isVelData);
else
- std::cerr << "Fluid Error -- updateParticlesFromFile(): Invalid file extension in file: "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateParticlesFromFile(): Invalid file extension in file: "
+ << filename << endl;
return false;
}
else {
- std::cerr << "Fluid Error -- updateParticlesFromFile(): Unable to open file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateParticlesFromFile(): Unable to open file: " << filename << endl;
return false;
}
}
-bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bool isVelData)
+bool MANTA::updateParticlesFromUni(string filename, bool isSecondarySys, bool isVelData)
{
if (with_debug)
- std::cout << "MANTA::updateParticlesFromUni()" << std::endl;
+ cout << "MANTA::updateParticlesFromUni()" << endl;
gzFile gzf;
int ibuffer[4];
gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb1"); // do some compression
if (!gzf) {
- std::cerr << "Fluid Error -- updateParticlesFromUni(): Unable to open file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateParticlesFromUni(): Unable to open file: " << filename << endl;
return false;
}
@@ -2697,24 +2536,24 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo
char file_magic[5] = {0, 0, 0, 0, 0};
readBytes = gzread(gzf, file_magic, 4);
if (!readBytes) {
- std::cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read header in file: "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read header in file: " << filename
+ << endl;
gzclose(gzf);
return false;
}
if (!strcmp(file_magic, "PB01")) {
- std::cerr << "Fluid Error -- updateParticlesFromUni(): Particle uni file format v01 not "
- "supported anymore."
- << std::endl;
+ cerr << "Fluid Error -- updateParticlesFromUni(): Particle uni file format v01 not "
+ "supported anymore."
+ << endl;
gzclose(gzf);
return false;
}
// Pointer to FLIP system or to secondary particle system
- std::vector<pData> *dataPointer = nullptr;
- std::vector<pVel> *velocityPointer = nullptr;
- std::vector<float> *lifePointer = nullptr;
+ vector<pData> *dataPointer = nullptr;
+ vector<pVel> *velocityPointer = nullptr;
+ vector<float> *lifePointer = nullptr;
if (isSecondarySys) {
dataPointer = mSndParticleData;
@@ -2740,19 +2579,19 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo
gzread(gzf, &timestamp, sizeof(unsigned long long));
if (with_debug)
- std::cout << "Fluid: Read " << ibuffer[0] << " particles in file: " << filename << std::endl;
+ cout << "Fluid: Read " << ibuffer[0] << " particles in file: " << filename << endl;
// Sanity checks
const int partSysSize = sizeof(float) * 3 + sizeof(int);
if (!(bytesPerElement == partSysSize) && (elementType == 0)) {
- std::cerr << "Fluid Error -- updateParticlesFromUni(): Invalid header in file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateParticlesFromUni(): Invalid header in file: " << filename
+ << endl;
gzclose(gzf);
return false;
}
if (!ibuffer[0]) { // Any particles present?
if (with_debug)
- std::cout << "Fluid: No particles present in file: " << filename << std::endl;
+ cout << "Fluid: No particles present in file: " << filename << endl;
gzclose(gzf);
return true; // return true since having no particles in a cache file is valid
}
@@ -2780,9 +2619,8 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo
readBytes = gzread(gzf, bufferPData, readLen * sizeof(pData));
if (!readBytes) {
- std::cerr
- << "Fluid Error -- updateParticlesFromUni(): Unable to read particle data in file: "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read particle data in file: "
+ << filename << endl;
MEM_freeN(bufferPData);
gzclose(gzf);
return false;
@@ -2794,7 +2632,7 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo
CLAMP(readEnd, 0, numParticles);
int k = 0;
- for (std::vector<MANTA::pData>::size_type j = readStart; j < readEnd; j++, k++) {
+ for (vector<MANTA::pData>::size_type j = readStart; j < readEnd; j++, k++) {
dataPointer->at(j).pos[0] = bufferPData[k].pos[0];
dataPointer->at(j).pos[1] = bufferPData[k].pos[1];
dataPointer->at(j).pos[2] = bufferPData[k].pos[2];
@@ -2821,9 +2659,9 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo
readBytes = gzread(gzf, bufferPVel, readLen * sizeof(pVel));
if (!readBytes) {
- std::cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read particle velocities "
- "in file: "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read particle velocities "
+ "in file: "
+ << filename << endl;
MEM_freeN(bufferPVel);
gzclose(gzf);
return false;
@@ -2835,7 +2673,7 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo
CLAMP(readEnd, 0, numParticles);
int k = 0;
- for (std::vector<MANTA::pVel>::size_type j = readStart; j < readEnd; j++, k++) {
+ for (vector<MANTA::pVel>::size_type j = readStart; j < readEnd; j++, k++) {
velocityPointer->at(j).pos[0] = bufferPVel[k].pos[0];
velocityPointer->at(j).pos[1] = bufferPVel[k].pos[1];
velocityPointer->at(j).pos[2] = bufferPVel[k].pos[2];
@@ -2860,9 +2698,8 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo
readBytes = gzread(gzf, bufferPLife, readLen * sizeof(float));
if (!readBytes) {
- std::cerr
- << "Fluid Error -- updateParticlesFromUni(): Unable to read particle life in file: "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read particle life in file: "
+ << filename << endl;
MEM_freeN(bufferPLife);
gzclose(gzf);
return false;
@@ -2874,7 +2711,7 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo
CLAMP(readEnd, 0, numParticles);
int k = 0;
- for (std::vector<float>::size_type j = readStart; j < readEnd; j++, k++) {
+ for (vector<float>::size_type j = readStart; j < readEnd; j++, k++) {
lifePointer->at(j) = bufferPLife[k];
}
todoParticles -= readLen;
@@ -2884,24 +2721,24 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo
return (gzclose(gzf) == Z_OK);
}
-bool MANTA::updateGridFromFile(std::string filename, float *grid, bool isNoise)
+bool MANTA::updateGridFromFile(string filename, float *grid, bool isNoise)
{
if (with_debug)
- std::cout << "MANTA::updateGridFromFile()" << std::endl;
+ cout << "MANTA::updateGridFromFile()" << endl;
if (!grid) {
- std::cerr << "Fluid Error -- updateGridFromFile(): Cannot read into uninitialized grid (grid "
- "is null)."
- << std::endl;
+ cerr << "Fluid Error -- updateGridFromFile(): Cannot read into uninitialized grid (grid "
+ "is null)."
+ << endl;
return false;
}
- std::string fname(filename);
- std::string::size_type idx;
+ string fname(filename);
+ string::size_type idx;
idx = fname.rfind('.');
- if (idx != std::string::npos) {
- std::string extension = fname.substr(idx + 1);
+ if (idx != string::npos) {
+ string extension = fname.substr(idx + 1);
if (extension.compare("uni") == 0)
return updateGridFromUni(filename, grid, isNoise);
@@ -2912,29 +2749,27 @@ bool MANTA::updateGridFromFile(std::string filename, float *grid, bool isNoise)
else if (extension.compare("raw") == 0)
return updateGridFromRaw(filename, grid, isNoise);
else
- std::cerr << "Fluid Error -- updateGridFromFile(): Invalid file extension in file: "
- << filename << std::endl;
+ cerr << "Fluid Error -- updateGridFromFile(): Invalid file extension in file: " << filename
+ << endl;
return false;
}
else {
- std::cerr << "Fluid Error -- updateGridFromFile(): Unable to open file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateGridFromFile(): Unable to open file: " << filename << endl;
return false;
}
}
-bool MANTA::updateGridFromUni(std::string filename, float *grid, bool isNoise)
+bool MANTA::updateGridFromUni(string filename, float *grid, bool isNoise)
{
if (with_debug)
- std::cout << "MANTA::updateGridFromUni()" << std::endl;
+ cout << "MANTA::updateGridFromUni()" << endl;
gzFile gzf;
int ibuffer[4];
gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb1");
if (!gzf) {
- std::cerr << "Fluid Error -- updateGridFromUni(): Unable to open file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateGridFromUni(): Unable to open file: " << filename << endl;
return false;
}
@@ -2942,32 +2777,29 @@ bool MANTA::updateGridFromUni(std::string filename, float *grid, bool isNoise)
char file_magic[5] = {0, 0, 0, 0, 0};
readBytes = gzread(gzf, file_magic, 4);
if (!readBytes) {
- std::cerr << "Fluid Error -- updateGridFromUni(): Unable to read header in file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateGridFromUni(): Unable to read header in file: " << filename
+ << endl;
gzclose(gzf);
return false;
}
if (!strcmp(file_magic, "DDF2")) {
- std::cerr
- << "Fluid Error -- updateGridFromUni(): Grid uni file format DDF2 not supported anymore."
- << std::endl;
+ cerr << "Fluid Error -- updateGridFromUni(): Grid uni file format DDF2 not supported anymore."
+ << endl;
gzclose(gzf);
return false;
}
if (!strcmp(file_magic, "MNT1")) {
- std::cerr
- << "Fluid Error -- updateGridFromUni(): Grid uni file format MNT1 not supported anymore."
- << std::endl;
+ cerr << "Fluid Error -- updateGridFromUni(): Grid uni file format MNT1 not supported anymore."
+ << endl;
gzclose(gzf);
return false;
}
if (!strcmp(file_magic, "MNT2")) {
- std::cerr
- << "Fluid Error -- updateGridFromUni(): Grid uni file format MNT2 not supported anymore."
- << std::endl;
+ cerr << "Fluid Error -- updateGridFromUni(): Grid uni file format MNT2 not supported anymore."
+ << endl;
gzclose(gzf);
return false;
}
@@ -2992,13 +2824,12 @@ bool MANTA::updateGridFromUni(std::string filename, float *grid, bool isNoise)
int resZ = (isNoise) ? mResZNoise : mResZ;
if (with_debug)
- std::cout << "Fluid: Read " << ibuffer[3] << " grid type in file: " << filename << std::endl;
+ cout << "Fluid: Read " << ibuffer[3] << " grid type in file: " << filename << endl;
// Sanity checks
if (ibuffer[0] != resX || ibuffer[1] != resY || ibuffer[2] != resZ) {
- std::cout << "Fluid: Grid dim doesn't match, read: (" << ibuffer[0] << ", " << ibuffer[1]
- << ", " << ibuffer[2] << ") vs setup: (" << resX << ", " << resY << ", " << resZ
- << ")" << std::endl;
+ cout << "Fluid: Grid dim doesn't match, read: (" << ibuffer[0] << ", " << ibuffer[1] << ", "
+ << ibuffer[2] << ") vs setup: (" << resX << ", " << resY << ", " << resZ << ")" << endl;
gzclose(gzf);
return false;
}
@@ -3009,16 +2840,16 @@ bool MANTA::updateGridFromUni(std::string filename, float *grid, bool isNoise)
}
if (with_debug)
- std::cout << "Fluid: Read successfully: " << filename << std::endl;
+ cout << "Fluid: Read successfully: " << filename << endl;
return (gzclose(gzf) == Z_OK);
}
#if OPENVDB == 1
-bool MANTA::updateGridFromVDB(std::string filename, float *grid, bool isNoise)
+bool MANTA::updateGridFromVDB(string filename, float *grid, bool isNoise)
{
if (with_debug)
- std::cout << "MANTA::updateGridFromVDB()" << std::endl;
+ cout << "MANTA::updateGridFromVDB()" << endl;
openvdb::initialize();
openvdb::io::File file(filename);
@@ -3026,8 +2857,8 @@ bool MANTA::updateGridFromVDB(std::string filename, float *grid, bool isNoise)
file.open();
}
catch (const openvdb::IoError &) {
- std::cerr << "Fluid Error -- updateGridFromVDB(): IOError, invalid OpenVDB file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateGridFromVDB(): IOError, invalid OpenVDB file: " << filename
+ << endl;
return false;
}
@@ -3059,17 +2890,17 @@ bool MANTA::updateGridFromVDB(std::string filename, float *grid, bool isNoise)
}
#endif
-bool MANTA::updateGridFromRaw(std::string filename, float *grid, bool isNoise)
+bool MANTA::updateGridFromRaw(string filename, float *grid, bool isNoise)
{
if (with_debug)
- std::cout << "MANTA::updateGridFromRaw()" << std::endl;
+ cout << "MANTA::updateGridFromRaw()" << endl;
gzFile gzf;
int expectedBytes, readBytes;
gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb");
if (!gzf) {
- std::cout << "MANTA::updateGridFromRaw(): unable to open file" << std::endl;
+ cout << "MANTA::updateGridFromRaw(): unable to open file" << endl;
return false;
}
@@ -3080,8 +2911,7 @@ bool MANTA::updateGridFromRaw(std::string filename, float *grid, bool isNoise)
expectedBytes = sizeof(float) * resX * resY * resZ;
readBytes = gzread(gzf, grid, expectedBytes);
if (!readBytes) {
- std::cerr << "Fluid Error -- updateGridFromRaw(): Unable to read raw file: " << filename
- << std::endl;
+ cerr << "Fluid Error -- updateGridFromRaw(): Unable to read raw file: " << filename << endl;
gzclose(gzf);
return false;
}
@@ -3094,25 +2924,25 @@ bool MANTA::updateGridFromRaw(std::string filename, float *grid, bool isNoise)
void MANTA::updatePointers()
{
if (with_debug)
- std::cout << "MANTA::updatePointers()" << std::endl;
-
- std::string func = "getDataPointer";
- std::string funcNodes = "getNodesDataPointer";
- std::string funcTris = "getTrisDataPointer";
-
- std::string id = std::to_string(mCurrentID);
- std::string solver = "s" + id;
- std::string parts = "pp" + id;
- std::string snd = "sp" + id;
- std::string mesh = "sm" + id;
- std::string mesh2 = "mesh" + id;
- std::string noise = "sn" + id;
- std::string solver_ext = "_" + solver;
- std::string parts_ext = "_" + parts;
- std::string snd_ext = "_" + snd;
- std::string mesh_ext = "_" + mesh;
- std::string mesh_ext2 = "_" + mesh2;
- std::string noise_ext = "_" + noise;
+ cout << "MANTA::updatePointers()" << endl;
+
+ string func = "getDataPointer";
+ string funcNodes = "getNodesDataPointer";
+ string funcTris = "getTrisDataPointer";
+
+ string id = to_string(mCurrentID);
+ string solver = "s" + id;
+ string parts = "pp" + id;
+ string snd = "sp" + id;
+ string mesh = "sm" + id;
+ string mesh2 = "mesh" + id;
+ string noise = "sn" + id;
+ string solver_ext = "_" + solver;
+ string parts_ext = "_" + parts;
+ string snd_ext = "_" + snd;
+ string mesh_ext = "_" + mesh;
+ string mesh_ext2 = "_" + mesh2;
+ string noise_ext = "_" + noise;
mFlags = (int *)pyObjectToPointer(callPythonFunction("flags" + solver_ext, func));
mPhiIn = (float *)pyObjectToPointer(callPythonFunction("phiIn" + solver_ext, func));
@@ -3199,27 +3029,27 @@ void MANTA::updatePointers()
}
if (mUsingLiquid) {
mPhi = (float *)pyObjectToPointer(callPythonFunction("phi" + solver_ext, func));
- mFlipParticleData = (std::vector<pData> *)pyObjectToPointer(
+ mFlipParticleData = (vector<pData> *)pyObjectToPointer(
callPythonFunction("pp" + solver_ext, func));
- mFlipParticleVelocity = (std::vector<pVel> *)pyObjectToPointer(
+ mFlipParticleVelocity = (vector<pVel> *)pyObjectToPointer(
callPythonFunction("pVel" + parts_ext, func));
}
if (mUsingLiquid && mUsingMesh) {
- mMeshNodes = (std::vector<Node> *)pyObjectToPointer(
+ mMeshNodes = (vector<Node> *)pyObjectToPointer(
callPythonFunction("mesh" + mesh_ext, funcNodes));
- mMeshTriangles = (std::vector<Triangle> *)pyObjectToPointer(
+ mMeshTriangles = (vector<Triangle> *)pyObjectToPointer(
callPythonFunction("mesh" + mesh_ext, funcTris));
}
if (mUsingLiquid && mUsingMVel) {
- mMeshVelocities = (std::vector<pVel> *)pyObjectToPointer(
+ mMeshVelocities = (vector<pVel> *)pyObjectToPointer(
callPythonFunction("mVel" + mesh_ext2, func));
}
if (mUsingLiquid && (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers)) {
- mSndParticleData = (std::vector<pData> *)pyObjectToPointer(
+ mSndParticleData = (vector<pData> *)pyObjectToPointer(
callPythonFunction("ppSnd" + snd_ext, func));
- mSndParticleVelocity = (std::vector<pVel> *)pyObjectToPointer(
+ mSndParticleVelocity = (vector<pVel> *)pyObjectToPointer(
callPythonFunction("pVelSnd" + parts_ext, func));
- mSndParticleLife = (std::vector<float> *)pyObjectToPointer(
+ mSndParticleLife = (vector<float> *)pyObjectToPointer(
callPythonFunction("pLifeSnd" + parts_ext, func));
}
@@ -3232,21 +3062,21 @@ void MANTA::updatePointers()
bool MANTA::hasConfig(FluidModifierData *mmd, int framenr)
{
- std::string extension = getCacheFileEnding(mmd->domain->cache_data_format);
+ string extension = getCacheFileEnding(mmd->domain->cache_data_format);
return BLI_exists(
getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, extension, framenr).c_str());
}
bool MANTA::hasData(FluidModifierData *mmd, int framenr)
{
- std::string filename = (mUsingSmoke) ? FLUID_DOMAIN_FILE_DENSITY : FLUID_DOMAIN_FILE_PP;
- std::string extension = getCacheFileEnding(mmd->domain->cache_data_format);
+ string filename = (mUsingSmoke) ? FLUID_DOMAIN_FILE_DENSITY : FLUID_DOMAIN_FILE_PP;
+ string extension = getCacheFileEnding(mmd->domain->cache_data_format);
return BLI_exists(getFile(mmd, FLUID_DOMAIN_DIR_DATA, filename, extension, framenr).c_str());
}
bool MANTA::hasNoise(FluidModifierData *mmd, int framenr)
{
- std::string extension = getCacheFileEnding(mmd->domain->cache_noise_format);
+ string extension = getCacheFileEnding(mmd->domain->cache_noise_format);
return BLI_exists(
getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_DENSITYNOISE, extension, framenr)
.c_str());
@@ -3254,14 +3084,14 @@ bool MANTA::hasNoise(FluidModifierData *mmd, int framenr)
bool MANTA::hasMesh(FluidModifierData *mmd, int framenr)
{
- std::string extension = getCacheFileEnding(mmd->domain->cache_mesh_format);
+ string extension = getCacheFileEnding(mmd->domain->cache_mesh_format);
return BLI_exists(
getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_DOMAIN_FILE_MESH, extension, framenr).c_str());
}
bool MANTA::hasParticles(FluidModifierData *mmd, int framenr)
{
- std::string extension = getCacheFileEnding(mmd->domain->cache_particle_format);
+ string extension = getCacheFileEnding(mmd->domain->cache_particle_format);
return BLI_exists(
getFile(mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_DOMAIN_FILE_PPSND, extension, framenr)
.c_str());
@@ -3269,13 +3099,13 @@ bool MANTA::hasParticles(FluidModifierData *mmd, int framenr)
bool MANTA::hasGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain)
{
- std::string subdirectory = (sourceDomain) ? FLUID_DOMAIN_DIR_DATA : FLUID_DOMAIN_DIR_GUIDE;
- std::string filename = (sourceDomain) ? FLUID_DOMAIN_FILE_VEL : FLUID_DOMAIN_FILE_GUIDEVEL;
- std::string extension = getCacheFileEnding(mmd->domain->cache_data_format);
+ string subdirectory = (sourceDomain) ? FLUID_DOMAIN_DIR_DATA : FLUID_DOMAIN_DIR_GUIDE;
+ string filename = (sourceDomain) ? FLUID_DOMAIN_FILE_VEL : FLUID_DOMAIN_FILE_GUIDEVEL;
+ string extension = getCacheFileEnding(mmd->domain->cache_data_format);
return BLI_exists(getFile(mmd, subdirectory, filename, extension, framenr).c_str());
}
-std::string MANTA::getDirectory(FluidModifierData *mmd, std::string subdirectory)
+string MANTA::getDirectory(FluidModifierData *mmd, string subdirectory)
{
char directory[FILE_MAX];
BLI_path_join(
@@ -3284,15 +3114,12 @@ std::string MANTA::getDirectory(FluidModifierData *mmd, std::string subdirectory
return directory;
}
-std::string MANTA::getFile(FluidModifierData *mmd,
- std::string subdirectory,
- std::string fname,
- std::string extension,
- int framenr)
+string MANTA::getFile(
+ FluidModifierData *mmd, string subdirectory, string fname, string extension, int framenr)
{
char targetFile[FILE_MAX];
- std::string path = getDirectory(mmd, subdirectory);
- std::string filename = fname + extension;
+ string path = getDirectory(mmd, subdirectory);
+ string filename = fname + extension;
BLI_join_dirfile(targetFile, sizeof(targetFile), path.c_str(), filename.c_str());
BLI_path_frame(targetFile, framenr, 0);
return targetFile;
diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h
index 21946431f28..9b3fd6aa141 100644
--- a/intern/mantaflow/intern/MANTA_main.h
+++ b/intern/mantaflow/intern/MANTA_main.h
@@ -27,8 +27,14 @@
#include <atomic>
#include <cassert>
#include <string>
+#include <unordered_map>
#include <vector>
+using std::atomic;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
struct MANTA {
public:
MANTA(int *res, struct FluidModifierData *mmd);
@@ -58,20 +64,20 @@ struct MANTA {
void step(struct FluidModifierData *mmd, int startFrame);
// Grid initialization functions
- void initHeat(struct FluidModifierData *mmd);
- void initFire(struct FluidModifierData *mmd);
- void initColors(struct FluidModifierData *mmd);
- void initFireHigh(struct FluidModifierData *mmd);
- void initColorsHigh(struct FluidModifierData *mmd);
- void initLiquid(FluidModifierData *mmd);
- void initLiquidMesh(FluidModifierData *mmd);
- void initObstacle(FluidModifierData *mmd);
- void initGuiding(FluidModifierData *mmd);
- void initFractions(FluidModifierData *mmd);
- void initInVelocity(FluidModifierData *mmd);
- void initOutflow(FluidModifierData *mmd);
- void initSndParts(FluidModifierData *mmd);
- void initLiquidSndParts(FluidModifierData *mmd);
+ void initHeat(struct FluidModifierData *mmd = NULL);
+ void initFire(struct FluidModifierData *mmd = NULL);
+ void initColors(struct FluidModifierData *mmd = NULL);
+ void initFireHigh(struct FluidModifierData *mmd = NULL);
+ void initColorsHigh(struct FluidModifierData *mmd = NULL);
+ void initLiquid(FluidModifierData *mmd = NULL);
+ void initLiquidMesh(FluidModifierData *mmd = NULL);
+ void initObstacle(FluidModifierData *mmd = NULL);
+ void initGuiding(FluidModifierData *mmd = NULL);
+ void initFractions(FluidModifierData *mmd = NULL);
+ void initInVelocity(FluidModifierData *mmd = NULL);
+ void initOutflow(FluidModifierData *mmd = NULL);
+ void initSndParts(FluidModifierData *mmd = NULL);
+ void initLiquidSndParts(FluidModifierData *mmd = NULL);
// Pointer transfer: Mantaflow -> Blender
void updatePointers();
@@ -414,7 +420,7 @@ struct MANTA {
return mPhi;
}
- static std::atomic<int> solverID;
+ static atomic<int> solverID;
static int with_debug; // on or off (1 or 0), also sets manta debug level
// Mesh getters
@@ -741,6 +747,8 @@ struct MANTA {
size_t mTotalCellsMesh;
size_t mTotalCellsParticles;
+ unordered_map<string, string> mRNAMap;
+
int mCurrentID;
bool mUsingHeat;
@@ -852,45 +860,46 @@ struct MANTA {
float *mPhi;
// Mesh fields
- std::vector<Node> *mMeshNodes;
- std::vector<Triangle> *mMeshTriangles;
- std::vector<pVel> *mMeshVelocities;
+ vector<Node> *mMeshNodes;
+ vector<Triangle> *mMeshTriangles;
+ vector<pVel> *mMeshVelocities;
// Particle fields
- std::vector<pData> *mFlipParticleData;
- std::vector<pVel> *mFlipParticleVelocity;
-
- std::vector<pData> *mSndParticleData;
- std::vector<pVel> *mSndParticleVelocity;
- std::vector<float> *mSndParticleLife;
-
- void initDomain(struct FluidModifierData *mmd);
- void initNoise(struct FluidModifierData *mmd);
- void initMesh(struct FluidModifierData *mmd);
- void initSmoke(struct FluidModifierData *mmd);
- void initSmokeNoise(struct FluidModifierData *mmd);
+ vector<pData> *mFlipParticleData;
+ vector<pVel> *mFlipParticleVelocity;
+
+ vector<pData> *mSndParticleData;
+ vector<pVel> *mSndParticleVelocity;
+ vector<float> *mSndParticleLife;
+
+ void initializeRNAMap(struct FluidModifierData *mmd = NULL);
+ void initDomain(struct FluidModifierData *mmd = NULL);
+ void initNoise(struct FluidModifierData *mmd = NULL);
+ void initMesh(struct FluidModifierData *mmd = NULL);
+ void initSmoke(struct FluidModifierData *mmd = NULL);
+ void initSmokeNoise(struct FluidModifierData *mmd = NULL);
void initializeMantaflow();
void terminateMantaflow();
- bool runPythonString(std::vector<std::string> commands);
- std::string getRealValue(const std::string &varName, FluidModifierData *mmd);
- std::string parseLine(const std::string &line, FluidModifierData *mmd);
- std::string parseScript(const std::string &setup_string, FluidModifierData *mmd = NULL);
- bool updateMeshFromBobj(std::string filename);
- bool updateMeshFromObj(std::string filename);
- bool updateMeshFromUni(std::string filename);
- bool updateParticlesFromUni(std::string filename, bool isSecondarySys, bool isVelData);
- bool updateGridFromUni(std::string filename, float *grid, bool isNoise);
- bool updateGridFromVDB(std::string filename, float *grid, bool isNoise);
- bool updateGridFromRaw(std::string filename, float *grid, bool isNoise);
- bool updateMeshFromFile(std::string filename);
- bool updateParticlesFromFile(std::string filename, bool isSecondarySys, bool isVelData);
- bool updateGridFromFile(std::string filename, float *grid, bool isNoise);
- std::string getDirectory(struct FluidModifierData *mmd, std::string subdirectory);
- std::string getFile(struct FluidModifierData *mmd,
- std::string subdirectory,
- std::string fname,
- std::string extension,
- int framenr);
+ bool runPythonString(vector<string> commands);
+ string getRealValue(const string &varName);
+ string parseLine(const string &line);
+ string parseScript(const string &setup_string, FluidModifierData *mmd = NULL);
+ bool updateMeshFromBobj(string filename);
+ bool updateMeshFromObj(string filename);
+ bool updateMeshFromUni(string filename);
+ bool updateParticlesFromUni(string filename, bool isSecondarySys, bool isVelData);
+ bool updateGridFromUni(string filename, float *grid, bool isNoise);
+ bool updateGridFromVDB(string filename, float *grid, bool isNoise);
+ bool updateGridFromRaw(string filename, float *grid, bool isNoise);
+ bool updateMeshFromFile(string filename);
+ bool updateParticlesFromFile(string filename, bool isSecondarySys, bool isVelData);
+ bool updateGridFromFile(string filename, float *grid, bool isNoise);
+ string getDirectory(struct FluidModifierData *mmd, string subdirectory);
+ string getFile(struct FluidModifierData *mmd,
+ string subdirectory,
+ string fname,
+ string extension,
+ int framenr);
};
#endif
diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h
index dd2111db7d7..c0a23f77d7a 100644
--- a/intern/mantaflow/intern/strings/fluid_script.h
+++ b/intern/mantaflow/intern/strings/fluid_script.h
@@ -92,7 +92,7 @@ const std::string fluid_variables =
mantaMsg('Fluid variables')\n\
dim_s$ID$ = $SOLVER_DIM$\n\
res_s$ID$ = $RES$\n\
-gravity_s$ID$ = vec3($GRAVITY_X$, $GRAVITY_Y$, $GRAVITY_Z$)\n\
+gravity_s$ID$ = vec3($GRAVITY_X$, $GRAVITY_Y$, $GRAVITY_Z$) # in SI unit (e.g. m/s^2)\n\
gs_s$ID$ = vec3($RESX$, $RESY$, $RESZ$)\n\
maxVel_s$ID$ = 0\n\
\n\
@@ -115,6 +115,7 @@ using_speedvectors_s$ID$ = $USING_SPEEDVECTORS$\n\
using_diffusion_s$ID$ = $USING_DIFFUSION$\n\
\n\
# Fluid time params\n\
+timeScale_s$ID$ = $TIME_SCALE$\n\
timeTotal_s$ID$ = $TIME_TOTAL$\n\
timePerFrame_s$ID$ = $TIME_PER_FRAME$\n\
frameLength_s$ID$ = $FRAME_LENGTH$\n\
@@ -132,8 +133,29 @@ end_frame_s$ID$ = $END_FRAME$\n\
domainSize_s$ID$ = $FLUID_DOMAIN_SIZE$ # longest domain side in meters\n\
viscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\
\n\
-# Factor to convert blender velocities to manta velocities\n\
-toMantaUnitsFac_s$ID$ = (1.0 / (1.0 / res_s$ID$))\n # = dt/dx * 1/dt ";
+# Factors to convert Blender units to Manta units\n\
+ratioMetersToRes_s$ID$ = float(domainSize_s$ID$) / float(res_s$ID$) # [meters / cells]\n\
+mantaMsg('1 Mantaflow cell is ' + str(ratioMetersToRes_s$ID$) + ' Blender length units long.')\n\
+\n\
+ratioResToBLength_s$ID$ = float(res_s$ID$) / float(domainSize_s$ID$) # [cells / blength] (blength: cm, m, or km, ... )\n\
+mantaMsg('1 Blender length unit is ' + str(ratioResToBLength_s$ID$) + ' Mantaflow cells long.')\n\
+\n\
+ratioBTimeToTimstep_s$ID$ = float(1) / float(0.1 * 25 * timeScale_s$ID$) # the time within 1 blender time unit, see also fluid.c\n\
+mantaMsg('1 Blender time unit is ' + str(ratioBTimeToTimstep_s$ID$) + ' Mantaflow time units long.')\n\
+\n\
+ratioFrameToFramelength_s$ID$ = float(1) / float(frameLength_s$ID$) # the time within 1 frame\n\
+mantaMsg('frame / frameLength is ' + str(ratioFrameToFramelength_s$ID$) + ' Mantaflow time units long.')\n\
+\n\
+scaleAcceleration_s$ID$ = ratioResToBLength_s$ID$ * (ratioBTimeToTimstep_s$ID$**2)# [meters/btime^2] to [cells/timestep^2] (btime: sec, min, or h, ...)\n\
+mantaMsg('scaleAcceleration is ' + str(scaleAcceleration_s$ID$))\n\
+\n\
+scaleSpeedFrames_s$ID$ = ratioResToBLength_s$ID$ * ratioFrameToFramelength_s$ID$ # [blength/frame] to [cells/frameLength]\n\
+mantaMsg('scaleSpeed is ' + str(scaleSpeedFrames_s$ID$))\n\
+\n\
+scaleSpeedTime_s$ID$ = ratioResToBLength_s$ID$ * ratioBTimeToTimstep_s$ID$ # [blength/btime] to [cells/frameLength]\n\
+mantaMsg('scaleSpeedTime is ' + str(scaleSpeedTime_s$ID$))\n\
+\n\
+gravity_s$ID$ *= scaleAcceleration_s$ID$ # scale from world acceleration to cell based acceleration\n";
const std::string fluid_variables_noise =
"\n\
@@ -342,17 +364,16 @@ def fluid_pre_step_$ID$():\n\
y_obvel_s$ID$.safeDivide(numObs_s$ID$)\n\
z_obvel_s$ID$.safeDivide(numObs_s$ID$)\n\
\n\
- x_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
- y_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
- z_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
- \n\
+ x_obvel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
+ y_obvel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
+ z_obvel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
copyRealToVec3(sourceX=x_obvel_s$ID$, sourceY=y_obvel_s$ID$, sourceZ=z_obvel_s$ID$, target=obvelC_s$ID$)\n\
\n\
# translate invels (world space) to grid space\n\
if using_invel_s$ID$:\n\
- x_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
- y_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
- z_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ x_invel_s$ID$.multConst(scaleSpeedTime_s$ID$)\n\
+ y_invel_s$ID$.multConst(scaleSpeedTime_s$ID$)\n\
+ z_invel_s$ID$.multConst(scaleSpeedTime_s$ID$)\n\
copyRealToVec3(sourceX=x_invel_s$ID$, sourceY=y_invel_s$ID$, sourceZ=z_invel_s$ID$, target=invelC_s$ID$)\n\
\n\
if using_guiding_s$ID$:\n\
@@ -362,9 +383,9 @@ def fluid_pre_step_$ID$():\n\
velT_s$ID$.multConst(vec3(gamma_sg$ID$))\n\
\n\
# translate external forces (world space) to grid space\n\
- x_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
- y_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
- z_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ x_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
+ y_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
+ z_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
copyRealToVec3(sourceX=x_force_s$ID$, sourceY=y_force_s$ID$, sourceZ=z_force_s$ID$, target=forces_s$ID$)\n\
\n\
# If obstacle has velocity, i.e. is a moving obstacle, switch to dynamic preconditioner\n\
@@ -598,10 +619,9 @@ def bake_guiding_process_$ID$(framenr, format_guiding, path_guiding, resumable):
y_guidevel_s$ID$.safeDivide(numGuides_s$ID$)\n\
z_guidevel_s$ID$.safeDivide(numGuides_s$ID$)\n\
\n\
- x_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\
- y_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\
- z_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\
- \n\
+ x_guidevel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
+ y_guidevel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
+ z_guidevel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
copyRealToVec3(sourceX=x_guidevel_s$ID$, sourceY=y_guidevel_s$ID$, sourceZ=z_guidevel_s$ID$, target=guidevelC_s$ID$)\n\
\n\
mantaMsg('Extrapolating guiding velocity')\n\
diff --git a/intern/mantaflow/intern/strings/liquid_script.h b/intern/mantaflow/intern/strings/liquid_script.h
index f20b218427c..ee1f0878687 100644
--- a/intern/mantaflow/intern/strings/liquid_script.h
+++ b/intern/mantaflow/intern/strings/liquid_script.h
@@ -68,7 +68,7 @@ c_s_sp$ID$ = 0.4 # classification constant for snd parts\n\
c_b_sp$ID$ = 0.77 # classification constant for snd parts\n\
pot_radius_sp$ID$ = $SNDPARTICLE_POTENTIAL_RADIUS$\n\
update_radius_sp$ID$ = $SNDPARTICLE_UPDATE_RADIUS$\n\
-scaleFromManta_sp$ID$ = $FLUID_DOMAIN_SIZE$ / float(res_s$ID$) # resize factor for snd parts\n";
+using_snd_pushout_sp$ID$ = $SNDPARTICLE_BOUNDARY_PUSHOUT$\n";
//////////////////////////////////////////////////////////////////////
// GRIDS & MESH & PARTICLESYSTEM
@@ -263,7 +263,7 @@ def liquid_step_$ID$():\n\
velOld_s$ID$.copyFrom(vel_s$ID$)\n\
\n\
# forces & pressure solve\n\
- addGravity(flags=flags_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$)\n\
+ addGravity(flags=flags_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, scale=False)\n\
\n\
mantaMsg('Adding external forces')\n\
addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\
@@ -371,10 +371,10 @@ def liquid_step_particles_$ID$():\n\
flags_sp$ID$.updateFromLevelset(levelset=phi_sp$ID$)\n\
\n\
# Actual secondary particle simulation\n\
- flipComputeSecondaryParticlePotentials(potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, normal=normal_sp$ID$, phi=phi_sp$ID$, radius=pot_radius_sp$ID$, tauMinTA=tauMin_ta_sp$ID$, tauMaxTA=tauMax_ta_sp$ID$, tauMinWC=tauMin_wc_sp$ID$, tauMaxWC=tauMax_wc_sp$ID$, tauMinKE=tauMin_k_sp$ID$, tauMaxKE=tauMax_k_sp$ID$, scaleFromManta=scaleFromManta_sp$ID$)\n\
+ flipComputeSecondaryParticlePotentials(potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, normal=normal_sp$ID$, phi=phi_sp$ID$, radius=pot_radius_sp$ID$, tauMinTA=tauMin_ta_sp$ID$, tauMaxTA=tauMax_ta_sp$ID$, tauMinWC=tauMin_wc_sp$ID$, tauMaxWC=tauMax_wc_sp$ID$, tauMinKE=tauMin_k_sp$ID$, tauMaxKE=tauMax_k_sp$ID$, scaleFromManta=ratioMetersToRes_s$ID$)\n\
flipSampleSecondaryParticles(mode='single', flags=flags_sp$ID$, v=vel_sp$ID$, pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, lMin=lMin_sp$ID$, lMax=lMax_sp$ID$, potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, k_ta=k_ta_sp$ID$, k_wc=k_wc_sp$ID$, dt=sp$ID$.timestep)\n\
flipUpdateSecondaryParticles(mode='linear', pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, f_sec=pForceSnd_pp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, neighborRatio=neighborRatio_sp$ID$, radius=update_radius_sp$ID$, gravity=gravity_s$ID$, k_b=k_b_sp$ID$, k_d=k_d_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, dt=sp$ID$.timestep)\n\
- if $SNDPARTICLE_BOUNDARY_PUSHOUT$:\n\
+ if using_snd_pushout_sp$ID$:\n\
pushOutofObs(parts=ppSnd_sp$ID$, flags=flags_sp$ID$, phiObs=phiObs_sp$ID$, shift=1.0)\n\
flipDeleteParticlesInObstacle(pts=ppSnd_sp$ID$, flags=flags_sp$ID$) # delete particles inside obstacle and outflow cells\n\
\n\
diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h
index fdb58543cec..ea2b1e9d848 100644
--- a/intern/mantaflow/intern/strings/smoke_script.h
+++ b/intern/mantaflow/intern/strings/smoke_script.h
@@ -376,9 +376,9 @@ def smoke_step_$ID$():\n\
\n\
if using_heat_s$ID$:\n\
mantaMsg('Adding heat buoyancy')\n\
- addBuoyancy(flags=flags_s$ID$, density=heat_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_heat_s$ID$)\n\
+ addBuoyancy(flags=flags_s$ID$, density=heat_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_heat_s$ID$, scale=False)\n\
mantaMsg('Adding buoyancy')\n\
- addBuoyancy(flags=flags_s$ID$, density=density_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_dens_s$ID$)\n\
+ addBuoyancy(flags=flags_s$ID$, density=density_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_dens_s$ID$, scale=False)\n\
\n\
mantaMsg('Adding forces')\n\
addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\
diff --git a/intern/string/STR_String.h b/intern/string/STR_String.h
deleted file mode 100644
index 97b23345f91..00000000000
--- a/intern/string/STR_String.h
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup string
- */
-
-#ifndef __STR_STRING_H__
-#define __STR_STRING_H__
-
-#ifndef STR_NO_ASSERTD
-# undef assertd
-# define assertd(exp) ((void)NULL)
-#endif
-
-#include <limits.h>
-#include <vector>
-
-#include <cstdlib>
-#include <cstring>
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-#ifdef _WIN32
-# define stricmp _stricmp
-#endif
-
-class STR_String;
-
-typedef unsigned long dword;
-typedef const STR_String &rcSTR_String;
-typedef unsigned char byte;
-
-/**
- * Smart String Value class. Is used by parser when an expression tree is build containing string.
- */
-
-class STR_String {
- public:
- // Initialization
- STR_String();
- STR_String(char c);
- STR_String(char c, int len);
- STR_String(const char *str);
- STR_String(const char *str, int len);
- STR_String(const STR_String &str);
- STR_String(const STR_String &str, int len);
- STR_String(const char *src1, int src1_len, const char *src2, int src2_len);
- explicit STR_String(int val);
- explicit STR_String(dword val);
- explicit STR_String(float val);
- explicit STR_String(double val);
- inline ~STR_String()
- {
- delete[] this->m_data;
- }
-
- // Operations
- STR_String &Format(const char *fmt, ...) // Set formatted text to string
-#ifdef __GNUC__
- __attribute__((format(printf, 2, 3)))
-#endif
- ;
- STR_String &FormatAdd(const char *fmt, ...) // Add formatted text to string
-#ifdef __GNUC__
- __attribute__((format(printf, 2, 3)))
-#endif
- ;
- inline void Clear()
- {
- this->m_len = this->m_data[0] = 0;
- }
- inline const STR_String &Reverse()
- {
- for (int i1 = 0, i2 = this->m_len - 1; i1 < i2; i1++, i2--) {
- std::swap(this->m_data[i1], this->m_data[i2]);
- }
- return *this;
- }
-
- // Properties
- bool IsUpper() const;
- bool IsLower() const;
- inline bool IsEmpty() const
- {
- return this->m_len == 0;
- }
- inline int Length() const
- {
- return this->m_len;
- }
-
- // Data access
- inline STR_String &SetLength(int len)
- {
- AllocBuffer(len, true);
- this->m_len = len;
- this->m_data[len] = 0;
- return *this;
- }
- inline char GetAt(int pos) const
- {
- assertd(pos < this->m_len);
- return this->m_data[pos];
- }
- inline void SetAt(int pos, char c)
- {
- assertd(pos < this->m_len);
- this->m_data[pos] = c;
- }
- inline void SetAt(int pos, rcSTR_String str);
- inline void SetAt(int pos, int num, rcSTR_String str);
- void Replace(int pos, rcSTR_String str);
- void Replace(int pos, int num, rcSTR_String str);
-
- // Substrings
- inline STR_String Left(int num) const
- {
- num = (num < this->m_len ? num : this->m_len);
- return STR_String(this->m_data, num);
- }
- inline STR_String Right(int num) const
- {
- num = (num < this->m_len ? num : this->m_len);
- return STR_String(this->m_data + this->m_len - num, num);
- }
- inline STR_String Mid(int pos, int num = INT_MAX) const
- {
- pos = (pos < this->m_len ? pos : this->m_len);
- num = (num < (this->m_len - pos) ? num : (this->m_len - pos));
- return STR_String(this->m_data + pos, num);
- }
-
- // Comparison
- int Compare(rcSTR_String rhs) const;
- int CompareNoCase(rcSTR_String rhs) const;
- inline bool IsEqual(rcSTR_String rhs) const
- {
- return (Compare(rhs) == 0);
- }
- inline bool IsEqualNoCase(rcSTR_String rhs) const
- {
- return (CompareNoCase(rhs) == 0);
- }
-
- // Search/replace
- int Find(char c, int pos = 0) const;
- int Find(const char *str, int pos = 0) const;
- int Find(rcSTR_String str, int pos = 0) const;
- int RFind(char c) const;
- int FindOneOf(const char *set, int pos = 0) const;
- int RFindOneOf(const char *set, int pos = 0) const;
-
- std::vector<STR_String> Explode(char c) const;
-
- // Formatting
- STR_String &Upper();
- STR_String &Lower();
- STR_String &Capitalize();
- STR_String &TrimLeft();
- STR_String &TrimLeft(char *set);
- STR_String &TrimRight();
- STR_String &TrimRight(char *set);
- STR_String &Trim();
- STR_String &Trim(char *set);
- STR_String &TrimQuotes();
-
- // Conversions
- // inline operator char*() { return this->m_data; }
- inline operator const char *() const
- {
- return this->m_data;
- }
- inline char *Ptr()
- {
- return this->m_data;
- }
- inline const char *ReadPtr() const
- {
- return this->m_data;
- }
- inline float ToFloat() const
- {
- float x = (float)(atof(this->m_data));
- return x;
- }
- inline int ToInt() const
- {
- return atoi(this->m_data);
- }
-
- // Operators
- inline rcSTR_String operator=(const byte *rhs)
- {
- return Copy((const char *)rhs, strlen((const char *)rhs));
- }
- inline rcSTR_String operator=(rcSTR_String rhs)
- {
- return Copy(rhs.ReadPtr(), rhs.Length());
- }
- inline rcSTR_String operator=(char rhs)
- {
- return Copy(&rhs, 1);
- }
- inline rcSTR_String operator=(const char *rhs)
- {
- return Copy(rhs, strlen(rhs));
- }
-
- inline rcSTR_String operator+=(const char *rhs)
- {
- return Concat(rhs, strlen(rhs));
- }
- inline rcSTR_String operator+=(rcSTR_String rhs)
- {
- return Concat(rhs.ReadPtr(), rhs.Length());
- }
- inline rcSTR_String operator+=(char rhs)
- {
- return Concat(&rhs, 1);
- }
-
- inline friend bool operator<(rcSTR_String lhs, rcSTR_String rhs)
- {
- return (strcmp(lhs, rhs) < 0);
- }
- inline friend bool operator<(rcSTR_String lhs, const char *rhs)
- {
- return (strcmp(lhs, rhs) < 0);
- }
- inline friend bool operator<(const char *lhs, rcSTR_String rhs)
- {
- return (strcmp(lhs, rhs) < 0);
- }
- inline friend bool operator>(rcSTR_String lhs, rcSTR_String rhs)
- {
- return (strcmp(lhs, rhs) > 0);
- }
- inline friend bool operator>(rcSTR_String lhs, const char *rhs)
- {
- return (strcmp(lhs, rhs) > 0);
- }
- inline friend bool operator>(const char *lhs, rcSTR_String rhs)
- {
- return (strcmp(lhs, rhs) > 0);
- }
- inline friend bool operator<=(rcSTR_String lhs, rcSTR_String rhs)
- {
- return (strcmp(lhs, rhs) <= 0);
- }
- inline friend bool operator<=(rcSTR_String lhs, const char *rhs)
- {
- return (strcmp(lhs, rhs) <= 0);
- }
- inline friend bool operator<=(const char *lhs, rcSTR_String rhs)
- {
- return (strcmp(lhs, rhs) <= 0);
- }
- inline friend bool operator>=(rcSTR_String lhs, rcSTR_String rhs)
- {
- return (strcmp(lhs, rhs) >= 0);
- }
- inline friend bool operator>=(rcSTR_String lhs, const char *rhs)
- {
- return (strcmp(lhs, rhs) >= 0);
- }
- inline friend bool operator>=(const char *lhs, rcSTR_String rhs)
- {
- return (strcmp(lhs, rhs) >= 0);
- }
- inline friend bool operator==(rcSTR_String lhs, rcSTR_String rhs)
- {
- return ((lhs.Length() == rhs.Length()) && (memcmp(lhs, rhs, lhs.Length()) == 0));
- }
- inline friend bool operator==(rcSTR_String lhs, const char *rhs)
- {
- return (strncmp(lhs, rhs, lhs.Length() + 1) == 0);
- }
- inline friend bool operator==(const char *lhs, rcSTR_String rhs)
- {
- return (strncmp(lhs, rhs, rhs.Length() + 1) == 0);
- }
- inline friend bool operator!=(rcSTR_String lhs, rcSTR_String rhs)
- {
- return ((lhs.Length() != rhs.Length()) || (memcmp(lhs, rhs, lhs.Length()) != 0));
- }
- inline friend bool operator!=(rcSTR_String lhs, const char *rhs)
- {
- return (strncmp(lhs, rhs, lhs.Length() + 1) != 0);
- }
- inline friend bool operator!=(const char *lhs, rcSTR_String rhs)
- {
- return (strncmp(lhs, rhs, rhs.Length() + 1) != 0);
- }
-
- // serializing
- // int Serialize(pCStream stream);
-
- protected:
- // Implementation
- void AllocBuffer(int len, bool keep_contents);
- rcSTR_String Copy(const char *src, int len);
- rcSTR_String Concat(const char *data, int len);
-
- static bool isLower(char c)
- {
- return !isUpper(c);
- }
- static bool isUpper(char c)
- {
- return (c >= 'A') && (c <= 'Z');
- }
- static bool isSpace(char c)
- {
- return (c == ' ') || (c == '\t');
- }
-
- char *m_data; // -> STR_String data
- int m_len; // z Data length
- int m_max; // Space in data buffer
-
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("CXX:STR_String")
-#endif
-};
-
-inline STR_String operator+(rcSTR_String lhs, rcSTR_String rhs)
-{
- return STR_String(lhs.ReadPtr(), lhs.Length(), rhs.ReadPtr(), rhs.Length());
-}
-inline STR_String operator+(rcSTR_String lhs, char rhs)
-{
- return STR_String(lhs.ReadPtr(), lhs.Length(), &rhs, 1);
-}
-inline STR_String operator+(char lhs, rcSTR_String rhs)
-{
- return STR_String(&lhs, 1, rhs.ReadPtr(), rhs.Length());
-}
-inline STR_String operator+(rcSTR_String lhs, const char *rhs)
-{
- return STR_String(lhs.ReadPtr(), lhs.Length(), rhs, strlen(rhs));
-}
-inline STR_String operator+(const char *lhs, rcSTR_String rhs)
-{
- return STR_String(lhs, strlen(lhs), rhs.ReadPtr(), rhs.Length());
-}
-
-#endif //__STR_STRING_H__
diff --git a/intern/string/intern/STR_String.cpp b/intern/string/intern/STR_String.cpp
deleted file mode 100644
index 306e786969b..00000000000
--- a/intern/string/intern/STR_String.cpp
+++ /dev/null
@@ -1,637 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup string
- *
- * Copyright (C) 2001 NaN Technologies B.V.
- * This file was formerly known as: GEN_StdString.cpp.
- */
-
-#include "STR_String.h"
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*-------------------------------------------------------------------------------------------------
- Construction / destruction
--------------------------------------------------------------------------------------------------*/
-
-#define STR_STRING_SIZE_DEFAULT_WORD 32 /* default size for a new word */
-#define STR_STRING_SIZE_DEFAULT_CHAR 9 /* default size for a new char */
-
-//
-// Construct an empty string
-//
-STR_String::STR_String()
- : m_data(new char[STR_STRING_SIZE_DEFAULT_WORD]), m_len(0), m_max(STR_STRING_SIZE_DEFAULT_WORD)
-{
- this->m_data[0] = 0;
-}
-
-//
-// Construct a string of one character
-//
-STR_String::STR_String(char c)
- : m_data(new char[STR_STRING_SIZE_DEFAULT_CHAR]), m_len(1), m_max(STR_STRING_SIZE_DEFAULT_CHAR)
-{
- this->m_data[0] = c;
- this->m_data[1] = 0;
-}
-
-//
-// Construct a string of multiple repeating characters
-//
-STR_String::STR_String(char c, int len) : m_data(new char[len + 8]), m_len(len), m_max(len + 8)
-{
- assertd(this->m_data != NULL);
- memset(this->m_data, c, len);
- this->m_data[len] = 0;
-}
-
-//
-// Construct a string from a pointer-to-ASCIIZ-string
-//
-// MAART: Changed to test for null strings
-STR_String::STR_String(const char *str)
-{
- if (str) {
- this->m_len = ::strlen(str);
- this->m_max = this->m_len + 8;
- this->m_data = new char[this->m_max];
- assertd(this->m_data != NULL);
- ::memcpy(this->m_data, str, this->m_len);
- this->m_data[this->m_len] = 0;
- }
- else {
- this->m_data = NULL;
- this->m_len = 0;
- this->m_max = 8;
- }
-}
-
-//
-// Construct a string from a pointer-to-ASCII-string and a length
-//
-STR_String::STR_String(const char *str, int len)
- : m_data(new char[len + 8]), m_len(len), m_max(len + 8)
-{
- assertd(this->m_data != NULL);
- memcpy(this->m_data, str, len);
- this->m_data[len] = 0;
-}
-
-//
-// Construct a string from another string
-//
-STR_String::STR_String(rcSTR_String str)
- : m_data(new char[str.Length() + 8]), m_len(str.Length()), m_max(str.Length() + 8)
-{
- assertd(this->m_data != NULL);
- assertd(str.this->m_data != NULL);
- memcpy(this->m_data, str.ReadPtr(), str.Length());
- this->m_data[str.Length()] = 0;
-}
-
-//
-// Construct a string from the first number of characters in another string
-//
-STR_String::STR_String(rcSTR_String str, int len)
- : m_data(new char[len + 8]), m_len(len), m_max(len + 8)
-{
- assertd(this->m_data != NULL);
- assertd(str.this->m_data != NULL);
- memcpy(this->m_data, str.ReadPtr(), str.Length());
- this->m_data[str.Length()] = 0;
-}
-
-//
-// Create a string by concatenating two sources
-//
-STR_String::STR_String(const char *src1, int len1, const char *src2, int len2)
- : m_data(new char[len1 + len2 + 8]), m_len(len1 + len2), m_max(len1 + len2 + 8)
-{
- assertd(this->m_data != NULL);
- memcpy(this->m_data, src1, len1);
- memcpy(this->m_data + len1, src2, len2);
- this->m_data[len1 + len2] = 0;
-}
-
-//
-// Create a string with an integer value
-//
-STR_String::STR_String(int val)
- : m_data(new char[STR_STRING_SIZE_DEFAULT_WORD]), m_max(STR_STRING_SIZE_DEFAULT_WORD)
-{
- assertd(this->m_data != NULL);
- this->m_len = sprintf(this->m_data, "%d", val);
-}
-
-//
-// Create a string with a dword value
-//
-STR_String::STR_String(dword val)
- : m_data(new char[STR_STRING_SIZE_DEFAULT_WORD]), m_max(STR_STRING_SIZE_DEFAULT_WORD)
-{
- assertd(this->m_data != NULL);
- this->m_len = sprintf(this->m_data, "%lu", val);
-}
-
-//
-// Create a string with a floating point value
-//
-STR_String::STR_String(float val)
- : m_data(new char[STR_STRING_SIZE_DEFAULT_WORD]), m_max(STR_STRING_SIZE_DEFAULT_WORD)
-{
- assertd(this->m_data != NULL);
- this->m_len = sprintf(this->m_data, "%g", val);
-}
-
-//
-// Create a string with a double value
-//
-STR_String::STR_String(double val)
- : m_data(new char[STR_STRING_SIZE_DEFAULT_WORD]), m_max(STR_STRING_SIZE_DEFAULT_WORD)
-{
- assertd(this->m_data != NULL);
- this->m_len = sprintf(this->m_data, "%g", val);
-}
-
-/*-------------------------------------------------------------------------------------------------
- Buffer management
--------------------------------------------------------------------------------------------------*/
-
-//
-// Make sure that the allocated buffer is at least <len> in size
-//
-void STR_String::AllocBuffer(int len, bool keep_contents)
-{
- // Check if we have enough space
- if (len + 1 <= this->m_max)
- return;
-
- // Reallocate string
- char *new_data = new char[len + 8];
- if (keep_contents) {
- memcpy(new_data, this->m_data, this->m_len);
- }
- delete[] this->m_data;
-
- // Accept new data
- this->m_max = len + 8;
- this->m_data = new_data;
- assertd(this->m_data != NULL);
-}
-
-/*-------------------------------------------------------------------------------------------------
- Basic string operations
--------------------------------------------------------------------------------------------------*/
-
-//
-// Format string (as does sprintf)
-//
-STR_String &STR_String::Format(const char *fmt, ...)
-{
- AllocBuffer(2048, false);
-
- assertd(this->m_data != NULL);
- // Expand arguments and format to string
- va_list args;
- va_start(args, fmt);
- this->m_len = vsprintf(this->m_data, fmt, args);
- assertd(this->m_len <= 2048);
- va_end(args);
-
- return *this;
-}
-
-//
-// Format string (as does sprintf)
-//
-STR_String &STR_String::FormatAdd(const char *fmt, ...)
-{
- AllocBuffer(2048, false);
-
- assertd(this->m_data != NULL);
- // Expand arguments and format to string
- va_list args;
- va_start(args, fmt);
- this->m_len += vsprintf(this->m_data + this->m_len, fmt, args);
- assertd(this->m_len <= 2048);
- va_end(args);
-
- return *this;
-}
-
-/*-------------------------------------------------------------------------------------------------
- Properties
--------------------------------------------------------------------------------------------------*/
-
-//
-// Check if string is entirely in UPPERCase
-//
-bool STR_String::IsUpper() const
-{
- for (int i = 0; i < this->m_len; i++)
- if (isLower(this->m_data[i]))
- return false;
-
- return true;
-}
-
-//
-// Check if string is entirely in lowerCase
-//
-bool STR_String::IsLower() const
-{
- for (int i = 0; i < this->m_len; i++)
- if (isUpper(this->m_data[i]))
- return false;
-
- return true;
-}
-
-/*-------------------------------------------------------------------------------------------------
- Search/Replace
--------------------------------------------------------------------------------------------------*/
-
-//
-// Find the first orccurence of <c> in the string
-//
-int STR_String::Find(char c, int pos) const
-{
- assertd(pos >= 0);
- assertd(this->m_len == 0 || pos < this->m_len);
- assertd(this->m_data != NULL);
- char *find_pos = strchr(this->m_data + pos, c);
- return (find_pos) ? (find_pos - this->m_data) : -1;
-}
-
-//
-// Find the first occurrence of <str> in the string
-//
-int STR_String::Find(const char *str, int pos) const
-{
- assertd(pos >= 0);
- assertd(this->m_len == 0 || pos < this->m_len);
- assertd(this->m_data != NULL);
- char *find_pos = strstr(this->m_data + pos, str);
- return (find_pos) ? (find_pos - this->m_data) : -1;
-}
-
-//
-// Find the first occurrence of <str> in the string
-//
-int STR_String::Find(rcSTR_String str, int pos) const
-{
- assertd(pos >= 0);
- assertd(this->m_len == 0 || pos < this->m_len);
- assertd(this->m_data != NULL);
- char *find_pos = strstr(this->m_data + pos, str.ReadPtr());
- return (find_pos) ? (find_pos - this->m_data) : -1;
-}
-
-//
-// Find the last occurrence of <c> in the string
-//
-int STR_String::RFind(char c) const
-{
- assertd(this->m_data != NULL);
- char *pos = strrchr(this->m_data, c);
- return (pos) ? (pos - this->m_data) : -1;
-}
-
-//
-// Find the first occurrence of any character in character set <set> in the string
-//
-int STR_String::FindOneOf(const char *set, int pos) const
-{
- assertd(pos >= 0);
- assertd(this->m_len == 0 || pos < this->m_len);
- assertd(this->m_data != NULL);
- char *find_pos = strpbrk(this->m_data + pos, set);
- return (find_pos) ? (find_pos - this->m_data) : -1;
-}
-
-//
-// Replace a character in this string with another string
-//
-void STR_String::Replace(int pos, rcSTR_String str)
-{
- // bounds(pos, 0, Length()-1);
-
- if (str.Length() < 1) {
- // Remove one character from the string
- memcpy(this->m_data + pos, this->m_data + pos + 1, this->m_len - pos);
- }
- else {
- // Insert zero or more characters into the string
- AllocBuffer(this->m_len + str.Length() - 1, true);
- if (str.Length() != 1)
- memcpy(this->m_data + pos + str.Length(), this->m_data + pos + 1, Length() - pos);
- memcpy(this->m_data + pos, str.ReadPtr(), str.Length());
- }
-
- this->m_len += str.Length() - 1;
-}
-
-//
-// Replace a substring of this string with another string
-//
-void STR_String::Replace(int pos, int num, rcSTR_String str)
-{
- // bounds(pos, 0, Length()-1);
- // bounds(pos+num, 0, Length());
- assertd(num >= 1);
-
- if (str.Length() < num) {
- // Remove some data from the string by replacement
- memcpy(
- this->m_data + pos + str.Length(), this->m_data + pos + num, this->m_len - pos - num + 1);
- memcpy(this->m_data + pos, str.ReadPtr(), str.Length());
- }
- else {
- // Insert zero or more characters into the string
- AllocBuffer(this->m_len + str.Length() - num, true);
- if (str.Length() != num)
- memcpy(
- this->m_data + pos + str.Length(), this->m_data + pos + num, Length() - pos - num + 1);
- memcpy(this->m_data + pos, str.ReadPtr(), str.Length());
- }
-
- this->m_len += str.Length() - num;
-}
-
-/*-------------------------------------------------------------------------------------------------
- Comparison
--------------------------------------------------------------------------------------------------*/
-
-//
-// Compare two strings and return the result,
-// <0 if *this<rhs, >0 if *this>rhs or 0 if *this==rhs
-//
-int STR_String::Compare(rcSTR_String rhs) const
-{
- return strcmp(this->ReadPtr(), rhs.ReadPtr());
-}
-
-//
-// Compare two strings without respecting case and return the result,
-// <0 if *this<rhs, >0 if *this>rhs or 0 if *this==rhs
-//
-int STR_String::CompareNoCase(rcSTR_String rhs) const
-{
-#ifdef WIN32
- return stricmp(this->ReadPtr(), rhs.ReadPtr());
-#else
- return strcasecmp(this->ReadPtr(), rhs.ReadPtr());
-#endif
-}
-
-/*-------------------------------------------------------------------------------------------------
- Formatting
--------------------------------------------------------------------------------------------------*/
-
-//
-// Capitalize string, "heLLo" -> "HELLO"
-//
-STR_String &STR_String::Upper()
-{
- assertd(this->m_data != NULL);
-#ifdef WIN32
- _strupr(this->m_data);
-#else
- for (int i = 0; i < this->m_len; i++)
- this->m_data[i] = (this->m_data[i] >= 'a' && this->m_data[i] <= 'z') ?
- this->m_data[i] + 'A' - 'a' :
- this->m_data[i];
-#endif
- return *this;
-}
-
-//
-// Lower string, "heLLo" -> "hello"
-//
-STR_String &STR_String::Lower()
-{
- assertd(this->m_data != NULL);
-#ifdef WIN32
- _strlwr(this->m_data);
-#else
- for (int i = 0; i < this->m_len; i++)
- this->m_data[i] = (this->m_data[i] >= 'A' && this->m_data[i] <= 'Z') ?
- this->m_data[i] + 'a' - 'A' :
- this->m_data[i];
-#endif
- return *this;
-}
-
-//
-// Capitalize string, "heLLo" -> "Hello"
-//
-STR_String &STR_String::Capitalize()
-{
- assertd(this->m_data != NULL);
-#ifdef WIN32
- if (this->m_len > 0)
- this->m_data[0] = toupper(this->m_data[0]);
- if (this->m_len > 1)
- _strlwr(this->m_data + 1);
-#else
- if (this->m_len > 0)
- this->m_data[0] = (this->m_data[0] >= 'a' && this->m_data[0] <= 'z') ?
- this->m_data[0] + 'A' - 'a' :
- this->m_data[0];
- for (int i = 1; i < this->m_len; i++)
- this->m_data[i] = (this->m_data[i] >= 'A' && this->m_data[i] <= 'Z') ?
- this->m_data[i] + 'a' - 'A' :
- this->m_data[i];
-#endif
- return *this;
-}
-
-//
-// Trim whitespace from the left side of the string
-//
-STR_String &STR_String::TrimLeft()
-{
- int skip;
- assertd(this->m_data != NULL);
- for (skip = 0; isSpace(this->m_data[skip]); skip++, this->m_len--) {
- /* pass */
- }
- memmove(this->m_data, this->m_data + skip, this->m_len + 1);
- return *this;
-}
-
-//
-// Trim whitespaces from the right side of the string
-//
-STR_String &STR_String::TrimRight()
-{
- assertd(this->m_data != NULL);
- while (this->m_len && isSpace(this->m_data[this->m_len - 1]))
- this->m_len--;
- this->m_data[this->m_len] = 0;
- return *this;
-}
-
-//
-// Trim spaces from both sides of the character set
-//
-STR_String &STR_String::Trim()
-{
- TrimRight();
- TrimLeft();
- return *this;
-}
-
-//
-// Trim characters from the character set <set> from the left side of the string
-//
-STR_String &STR_String::TrimLeft(char *set)
-{
- int skip;
- assertd(this->m_data != NULL);
- for (skip = 0; this->m_len && strchr(set, this->m_data[skip]); skip++, this->m_len--) {
- /* pass */
- }
- memmove(this->m_data, this->m_data + skip, this->m_len + 1);
- return *this;
-}
-
-//
-// Trim characters from the character set <set> from the right side of the string
-//
-STR_String &STR_String::TrimRight(char *set)
-{
- assertd(this->m_data != NULL);
- while (this->m_len && strchr(set, this->m_data[this->m_len - 1]))
- this->m_len--;
- this->m_data[this->m_len] = 0;
- return *this;
-}
-
-//
-// Trim characters from the character set <set> from both sides of the character set
-//
-STR_String &STR_String::Trim(char *set)
-{
- TrimRight(set);
- TrimLeft(set);
- return *this;
-}
-
-//
-// Trim quotes from both sides of the string
-//
-STR_String &STR_String::TrimQuotes()
-{
- // Trim quotes if they are on both sides of the string
- assertd(this->m_data != NULL);
- if ((this->m_len >= 2) && (this->m_data[0] == '\"') && (this->m_data[this->m_len - 1] == '\"')) {
- memmove(this->m_data, this->m_data + 1, this->m_len - 2 + 1);
- this->m_len -= 2;
- }
- return *this;
-}
-
-/*-------------------------------------------------------------------------------------------------
- Assignment/Concatenation
--------------------------------------------------------------------------------------------------*/
-
-//
-// Set the string's conents to a copy of <src> with length <len>
-//
-rcSTR_String STR_String::Copy(const char *src, int len)
-{
- assertd(len >= 0);
- assertd(src);
- assertd(this->m_data != NULL);
-
- AllocBuffer(len, false);
- this->m_len = len;
- memcpy(this->m_data, src, len);
- this->m_data[this->m_len] = 0;
-
- return *this;
-}
-
-//
-// Concate a number of bytes to the current string
-//
-rcSTR_String STR_String::Concat(const char *data, int len)
-{
- assertd(this->m_len >= 0);
- assertd(len >= 0);
- assertd(data);
- assertd(this->m_data != NULL);
-
- AllocBuffer(this->m_len + len, true);
- memcpy(this->m_data + this->m_len, data, len);
- this->m_len += len;
- this->m_data[this->m_len] = 0;
-
- return *this;
-}
-
-std::vector<STR_String> STR_String::Explode(char c) const
-{
- STR_String lcv = *this;
- std::vector<STR_String> uc;
-
- while (lcv.Length()) {
- int pos = lcv.Find(c);
- if (pos < 0) {
- uc.push_back(lcv);
- lcv.Clear();
- }
- else {
- uc.push_back(lcv.Left(pos));
- lcv = lcv.Mid(pos + 1);
- }
- }
-
- // uc. -= STR_String("");
-
- return uc;
-}
-
-#if 0
-
-int STR_String::Serialize(pCStream stream)
-{
- if (stream->GetAccess() == CStream::Access_Read) {
- int ln;
- stream->Read(&ln, sizeof(ln));
- AllocBuffer(ln, false);
- stream->Read(this->m_data, ln);
- this->m_data[ln] = '\0';
- this->m_len = ln;
- }
- else {
- stream->Write(&this->m_len, sizeof(this->m_len));
- stream->Write(this->m_data, this->m_len);
- }
-
- return this->m_len + sizeof(this->m_len);
-}
-#endif
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index de3583db2bb..4d48bb8eaac 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -279,8 +279,8 @@ const bTheme U_theme_default = {
.button_text_hi = RGBA(0xffffffff),
.navigation_bar = RGBA(0x232323ff),
.panelcolors = {
- .header = RGBA(0x42424200),
- .back = RGBA(0x00000028),
+ .header = RGBA(0x424242ff),
+ .back = RGBA(0x383838ff),
.sub_back = RGBA(0x00000024),
},
.vertex_size = 3,
@@ -697,7 +697,7 @@ const bTheme U_theme_default = {
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 3,
- .editmesh_active = RGBA(0xffffff80),
+ .editmesh_active = RGBA(0xffffff40),
.handle_vertex_select = RGBA(0xffff00ff),
.handle_vertex_size = 5,
.gp_vertex_size = 3,
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 44c17b01168ea180d7ea865e9ec1ef6e93097b3
+Subproject 136030c95656db371add0c5b7878f6442b8f24e
diff --git a/release/scripts/modules/rna_keymap_ui.py b/release/scripts/modules/rna_keymap_ui.py
index 22be5186186..844daded570 100644
--- a/release/scripts/modules/rna_keymap_ui.py
+++ b/release/scripts/modules/rna_keymap_ui.py
@@ -161,7 +161,12 @@ def draw_kmi(display_keymaps, kc, km, kmi, layout, level):
if (not kmi.is_user_defined) and kmi.is_user_modified:
row.operator("preferences.keyitem_restore", text="", icon='BACK').item_id = kmi.id
else:
- row.operator("preferences.keyitem_remove", text="", icon='X').item_id = kmi.id
+ row.operator(
+ "preferences.keyitem_remove",
+ text="",
+ # Abusing the tracking icon, but it works pretty well here.
+ icon=('TRACKING_CLEAR_BACKWARDS' if kmi.is_user_defined else 'X')
+ ).item_id = kmi.id
# Expanded, additional event settings
if kmi.show_expanded:
diff --git a/release/scripts/presets/interface_theme/blender_light.xml b/release/scripts/presets/interface_theme/blender_light.xml
index f4ec8233df3..48ad0a8367e 100644
--- a/release/scripts/presets/interface_theme/blender_light.xml
+++ b/release/scripts/presets/interface_theme/blender_light.xml
@@ -724,7 +724,7 @@
freestyle_face_mark="#7fff7f33"
face_back="#00000000"
face_front="#00000000"
- editmesh_active="#ffffff80"
+ editmesh_active="#ffffff40"
wire_edit="#c0c0c0"
edge_select="#ff8500"
scope_back="#727272ff"
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 07916fa9799..604c5231df2 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -798,8 +798,8 @@ def km_outliner(params):
("outliner.drivers_add_selected", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("outliner.drivers_delete_selected", {"type": 'D', "value": 'PRESS', "ctrl": True, "alt": True}, None),
("outliner.collection_new", {"type": 'C', "value": 'PRESS'}, None),
- ("outliner.collection_delete", {"type": 'X', "value": 'PRESS'}, None),
- ("outliner.collection_delete", {"type": 'DEL', "value": 'PRESS'}, None),
+ ("outliner.delete", {"type": 'X', "value": 'PRESS'}, None),
+ ("outliner.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("object.move_to_collection", {"type": 'M', "value": 'PRESS'}, None),
("object.link_to_collection", {"type": 'M', "value": 'PRESS', "shift": True}, None),
("outliner.collection_exclude_set", {"type": 'E', "value": 'PRESS'}, None),
@@ -3226,6 +3226,8 @@ def km_grease_pencil_stroke_paint_mode(params):
{"properties": [("unselected", True)]}),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
+ # Active material
+ op_menu("GPENCIL_MT_material_active", {"type": 'U', "value": 'PRESS'}),
# Keyframe menu
op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}),
# Draw context menu
@@ -5873,6 +5875,23 @@ def km_3d_view_tool_edit_mesh_extrude_region(params):
]},
)
+def km_3d_view_tool_edit_mesh_extrude_dissolve_and_intersect(params):
+ return (
+ "3D View Tool: Edit Mesh, Extrude Dissolve and Intersect",
+ {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
+ {"items": [
+ ("mesh.extrude_region_dissolve_move_intersect", {"type": params.tool_tweak, "value": 'ANY'},
+ {"properties": [
+ ("MESH_OT_extrude_region", [("use_dissolve_ortho_edges", True)]),
+ ("TRANSFORM_OT_translate", [
+ ("release_confirm", True),
+ ("use_automerge_and_split", True),
+ ("constraint_axis", (False, False, True)),
+ ("orient_type", 'NORMAL'),
+ ]),
+ ]}),
+ ]},
+ )
def km_3d_view_tool_edit_mesh_extrude_along_normals(params):
return (
@@ -6723,6 +6742,7 @@ def generate_keymaps(params=None):
km_3d_view_tool_edit_armature_extrude_to_cursor(params),
km_3d_view_tool_edit_mesh_add_cube(params),
km_3d_view_tool_edit_mesh_extrude_region(params),
+ km_3d_view_tool_edit_mesh_extrude_dissolve_and_intersect(params),
km_3d_view_tool_edit_mesh_extrude_along_normals(params),
km_3d_view_tool_edit_mesh_extrude_individual(params),
km_3d_view_tool_edit_mesh_extrude_to_cursor(params),
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index 0005e7dd3d2..842a12ed249 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -520,10 +520,8 @@ def km_outliner(params):
("anim.keyframe_delete", {"type": 'S', "value": 'PRESS', "alt": True}, None),
("outliner.drivers_add_selected", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("outliner.drivers_delete_selected", {"type": 'D', "value": 'PRESS', "ctrl": True, "alt": True}, None),
- ("outliner.collection_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
- ("outliner.collection_delete", {"type": 'DEL', "value": 'PRESS'}, None),
- ("outliner.object_operation", {"type": 'BACK_SPACE', "value": 'PRESS'}, {"properties": [("type", 'DELETE')]}),
- ("outliner.object_operation", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("type", 'DELETE')]}),
+ ("outliner.delete", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
+ ("outliner.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("object.move_to_collection", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
("object.link_to_collection", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("outliner.collection_exclude_set", {"type": 'E', "value": 'PRESS'}, None),
@@ -2376,7 +2374,7 @@ def km_grease_pencil_stroke_paint_mode(params):
op_tool_cycle("builtin.cutter", {"type": 'K', "value": 'PRESS'}),
op_tool_cycle("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
# Active layer
- op_menu("GPENCIL_MT_layer_active", {"type": 'M', "value": 'PRESS'}),
+ op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Keyframe menu
op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}),
])
@@ -3377,6 +3375,10 @@ def km_sculpt(params):
# Remesh
("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("object.quadriflow_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True, "alt": True}, None),
+ # Remesh
+ ("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("object.voxel_size_edit", {"type": 'R', "value": 'PRESS', "shift": True}, None),
+ ("object.quadriflow_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True, "alt": True}, None),
# Brush properties
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
{"properties": [("scalar", 0.9)]}),
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index 5af2bd22222..d7df29f1769 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -42,6 +42,7 @@ _modules = [
"rigidbody",
"screen_play_rendered_anim",
"sequencer",
+ "simulation",
"userpref",
"uvcalc_follow_active",
"uvcalc_lightmap",
diff --git a/release/scripts/startup/bl_operators/simulation.py b/release/scripts/startup/bl_operators/simulation.py
new file mode 100644
index 00000000000..5d9c9476318
--- /dev/null
+++ b/release/scripts/startup/bl_operators/simulation.py
@@ -0,0 +1,39 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+
+class NewSimulation(bpy.types.Operator):
+ """Create a new simulation data block and edit it in the opened simulation editor"""
+
+ bl_idname = "simulation.new"
+ bl_label = "New Simulation"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.area.type == 'NODE_EDITOR' and context.space_data.tree_type == 'SimulationNodeTree'
+
+ def execute(self, context):
+ simulation = bpy.data.simulations.new("Simulation")
+ context.space_data.simulation = simulation
+ return {'FINISHED'}
+
+classes = (
+ NewSimulation,
+)
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index f78ee026927..a4c19d5a8da 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -110,20 +110,30 @@ class PREFERENCES_OT_copy_prev(Operator):
bl_idname = "preferences.copy_prev"
bl_label = "Copy Previous Settings"
- @staticmethod
- def previous_version():
- ver = bpy.app.version
- ver_old = ((ver[0] * 100) + ver[1]) - 1
- return ver_old // 100, ver_old % 100
+ @classmethod
+ def _old_version_path(cls, version):
+ return bpy.utils.resource_path('USER', version[0], version[1])
- @staticmethod
- def _old_path():
- ver = bpy.app.version
- ver_old = ((ver[0] * 100) + ver[1]) - 1
- return bpy.utils.resource_path('USER', ver_old // 100, ver_old % 100)
+ @classmethod
+ def previous_version(cls):
+ # Find config folder from previous version.
+ import os
+ version = bpy.app.version
+ version_old = ((version[0] * 100) + version[1]) - 1
+ while version_old % 10 > 0:
+ version_split = version_old // 100, version_old % 100
+ if os.path.isdir(cls._old_version_path(version_split)):
+ return version_split
+ version_old = version_old - 1
+ return None
- @staticmethod
- def _new_path():
+ @classmethod
+ def _old_path(cls):
+ version_old = cls.previous_version()
+ return cls._old_version_path(version_old) if version_old else None
+
+ @classmethod
+ def _new_path(cls):
return bpy.utils.resource_path('USER')
@classmethod
@@ -132,6 +142,8 @@ class PREFERENCES_OT_copy_prev(Operator):
old = cls._old_path()
new = cls._new_path()
+ if not old:
+ return False
# Disable operator in case config path is overridden with environment
# variable. That case has no automatic per-version configuration.
diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py
index fcabee94a89..88fa06a913f 100644
--- a/release/scripts/startup/bl_operators/view3d.py
+++ b/release/scripts/startup/bl_operators/view3d.py
@@ -72,13 +72,19 @@ class VIEW3D_OT_edit_mesh_extrude_move(Operator):
bl_label = "Extrude and Move on Normals"
bl_idname = "view3d.edit_mesh_extrude_move_normal"
+ dissolve_and_intersect: BoolProperty(
+ name="dissolve_and_intersect",
+ default=False,
+ description="Dissolves adjacent faces and intersects new geometry"
+ )
+
@classmethod
def poll(cls, context):
obj = context.active_object
return (obj is not None and obj.mode == 'EDIT')
@staticmethod
- def extrude_region(context, use_vert_normals):
+ def extrude_region(context, use_vert_normals, dissolve_and_intersect):
mesh = context.object.data
totface = mesh.total_face_sel
@@ -91,6 +97,17 @@ class VIEW3D_OT_edit_mesh_extrude_move(Operator):
'INVOKE_REGION_WIN',
TRANSFORM_OT_shrink_fatten={},
)
+ elif dissolve_and_intersect:
+ bpy.ops.mesh.extrude_region_dissolve_move_intersect(
+ 'INVOKE_REGION_WIN',
+ MESH_OT_extrude_region={
+ "use_dissolve_ortho_edges": True,
+ },
+ TRANSFORM_OT_translate={
+ "orient_type": 'NORMAL',
+ "constraint_axis": (False, False, True),
+ },
+ )
else:
bpy.ops.mesh.extrude_region_move(
'INVOKE_REGION_WIN',
@@ -119,7 +136,7 @@ class VIEW3D_OT_edit_mesh_extrude_move(Operator):
return {'FINISHED'}
def execute(self, context):
- return VIEW3D_OT_edit_mesh_extrude_move.extrude_region(context, False)
+ return VIEW3D_OT_edit_mesh_extrude_move.extrude_region(context, False, self.dissolve_and_intersect)
def invoke(self, context, _event):
return self.execute(context)
@@ -136,7 +153,7 @@ class VIEW3D_OT_edit_mesh_extrude_shrink_fatten(Operator):
return (obj is not None and obj.mode == 'EDIT')
def execute(self, context):
- return VIEW3D_OT_edit_mesh_extrude_move.extrude_region(context, True)
+ return VIEW3D_OT_edit_mesh_extrude_move.extrude_region(context, True, False)
def invoke(self, context, _event):
return self.execute(context)
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 70d958b9bc8..9e2ce8b83ad 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -2485,8 +2485,8 @@ class WM_MT_splash(Menu):
row = layout.row()
sub = row.row()
- if bpy.types.PREFERENCES_OT_copy_prev.poll(context):
- old_version = bpy.types.PREFERENCES_OT_copy_prev.previous_version()
+ old_version = bpy.types.PREFERENCES_OT_copy_prev.previous_version()
+ if bpy.types.PREFERENCES_OT_copy_prev.poll(context) and old_version:
sub.operator("preferences.copy_prev", text="Load %d.%d Settings" % old_version)
sub.operator("wm.save_userpref", text="Save New Settings")
else:
diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py
index d44af702d46..05abfa02500 100644
--- a/release/scripts/startup/bl_ui/properties_data_armature.py
+++ b/release/scripts/startup/bl_ui/properties_data_armature.py
@@ -84,17 +84,12 @@ class DATA_PT_display(ArmatureButtonsPanel, Panel):
layout.prop(arm, "display_type", text="Display As")
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=True)
- col = flow.column()
+ col = layout.column(heading="Show")
col.prop(arm, "show_names", text="Names")
- col = flow.column()
col.prop(arm, "show_axes", text="Axes")
- col = flow.column()
col.prop(arm, "show_bone_custom_shapes", text="Shapes")
- col = flow.column()
col.prop(arm, "show_group_colors", text="Group Colors")
if ob:
- col = flow.column()
col.prop(ob, "show_in_front", text="In Front")
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index aee909e3a6c..62dffa3b6ba 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -360,8 +360,9 @@ class DATA_PT_camera_background_image(CameraButtonsPanel, Panel):
col.prop(bg, "rotation")
col.prop(bg, "scale")
- col.prop(bg, "use_flip_x")
- col.prop(bg, "use_flip_y")
+ col = box.column(heading="Flip")
+ col.prop(bg, "use_flip_x", text="X")
+ col.prop(bg, "use_flip_y", text="Y")
class DATA_PT_camera_display(CameraButtonsPanel, Panel):
@@ -377,21 +378,12 @@ class DATA_PT_camera_display(CameraButtonsPanel, Panel):
col = layout.column(align=True)
- col.separator()
-
col.prop(cam, "display_size", text="Size")
- col.separator()
-
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False)
-
- col = flow.column()
+ col = layout.column(heading="Show")
col.prop(cam, "show_limits", text="Limits")
- col = flow.column()
col.prop(cam, "show_mist", text="Mist")
- col = flow.column()
col.prop(cam, "show_sensor", text="Sensor")
- col = flow.column()
col.prop(cam, "show_name", text="Name")
@@ -407,24 +399,20 @@ class DATA_PT_camera_display_composition_guides(CameraButtonsPanel, Panel):
cam = context.camera
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False)
+ layout.prop(cam, "show_composition_thirds")
- col = flow.column()
+ col = layout.column(heading="Center", align=True)
col.prop(cam, "show_composition_center")
- col = flow.column()
- col.prop(cam, "show_composition_center_diagonal")
- col = flow.column()
- col.prop(cam, "show_composition_thirds")
- col = flow.column()
- col.prop(cam, "show_composition_golden")
- col = flow.column()
- col.prop(cam, "show_composition_golden_tria_a")
- col = flow.column()
- col.prop(cam, "show_composition_golden_tria_b")
- col = flow.column()
- col.prop(cam, "show_composition_harmony_tri_a")
- col = flow.column()
- col.prop(cam, "show_composition_harmony_tri_b")
+ col.prop(cam, "show_composition_center_diagonal", text="Diagonal")
+
+ col = layout.column(heading="Golden", align=True)
+ col.prop(cam, "show_composition_golden", text="Ratio")
+ col.prop(cam, "show_composition_golden_tria_a", text="Triangle A")
+ col.prop(cam, "show_composition_golden_tria_b", text="Triangle B")
+
+ col = layout.column(heading="Harmony", align=True)
+ col.prop(cam, "show_composition_harmony_tri_a", text="Triangle A")
+ col.prop(cam, "show_composition_harmony_tri_b", text="Triangle B")
class DATA_PT_camera_display_passepartout(CameraButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index b694062dfc5..7e7488f4cf1 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -276,23 +276,23 @@ class DATA_PT_active_spline(CurveButtonsPanelActive, Panel):
col.prop(act_spline, "use_smooth")
else:
- sub = col.column(align=True)
- sub.prop(act_spline, "use_cyclic_u")
+ sub = col.column(heading="Cyclic", align=True)
+ sub.prop(act_spline, "use_cyclic_u", text="U")
if is_surf:
sub.prop(act_spline, "use_cyclic_v", text="V")
if act_spline.type == 'NURBS':
- sub = col.column(align=True)
+ sub = col.column(heading="Bezier", align=True)
# sub.active = (not act_spline.use_cyclic_u)
- sub.prop(act_spline, "use_bezier_u", text="Bezier U")
+ sub.prop(act_spline, "use_bezier_u", text="U")
if is_surf:
subsub = sub.column()
subsub.active = (not act_spline.use_cyclic_v)
subsub.prop(act_spline, "use_bezier_v", text="V")
- sub = col.column(align=True)
- sub.prop(act_spline, "use_endpoint_u", text="Endpoint U")
+ sub = col.column(heading="Endpoint", align=True)
+ sub.prop(act_spline, "use_endpoint_u", text="U")
if is_surf:
subsub = sub.column()
diff --git a/release/scripts/startup/bl_ui/properties_data_empty.py b/release/scripts/startup/bl_ui/properties_data_empty.py
index 898ab2e4359..1523f69536f 100644
--- a/release/scripts/startup/bl_ui/properties_data_empty.py
+++ b/release/scripts/startup/bl_ui/properties_data_empty.py
@@ -53,9 +53,11 @@ class DATA_PT_empty(DataButtonsPanel, Panel):
depth_row.enabled = not ob.show_in_front
depth_row.prop(ob, "empty_image_depth", text="Depth", expand=True)
col.row().prop(ob, "empty_image_side", text="Side", expand=True)
- col.prop(ob, "show_empty_image_orthographic", text="Display Orthographic")
- col.prop(ob, "show_empty_image_perspective", text="Display Perspective")
- col.prop(ob, "show_empty_image_only_axis_aligned")
+
+ col = layout.column(heading="Show in", align=True)
+ col.prop(ob, "show_empty_image_orthographic", text="Orthographic")
+ col.prop(ob, "show_empty_image_perspective", text="Perspective")
+ col.prop(ob, "show_empty_image_only_axis_aligned", text="Only Axis Aligned")
class DATA_PT_empty_alpha(DataButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index d91b2ceb7f7..425c94dfdcd 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -190,27 +190,20 @@ class DATA_PT_normals(MeshButtonsPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
def draw(self, context):
- pass
-
-
-class DATA_PT_normals_auto_smooth(MeshButtonsPanel, Panel):
- bl_label = "Auto Smooth"
- bl_parent_id = "DATA_PT_normals"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- def draw_header(self, context):
- mesh = context.mesh
-
- self.layout.prop(mesh, "use_auto_smooth", text="")
-
- def draw(self, context):
layout = self.layout
layout.use_property_split = True
mesh = context.mesh
- layout.active = mesh.use_auto_smooth and not mesh.has_custom_normals
- layout.prop(mesh, "auto_smooth_angle", text="Angle")
+ col = layout.column(align=False, heading="Auto Smooth")
+ col.use_property_decorate = False
+ row = col.row(align=True)
+ sub = row.row(align=True)
+ sub.prop(mesh, "use_auto_smooth", text="")
+ sub = sub.row(align=True)
+ sub.active = mesh.use_auto_smooth and not mesh.has_custom_normals
+ sub.prop(mesh, "auto_smooth_angle", text="")
+ row.prop_decorator(mesh, "auto_smooth_angle")
class DATA_PT_texture_space(MeshButtonsPanel, Panel):
@@ -485,9 +478,11 @@ class DATA_PT_remesh(MeshButtonsPanel, Panel):
col.prop(mesh, "remesh_voxel_adaptivity")
col.prop(mesh, "use_remesh_fix_poles")
col.prop(mesh, "use_remesh_smooth_normals")
- col.prop(mesh, "use_remesh_preserve_volume")
- col.prop(mesh, "use_remesh_preserve_paint_mask")
- col.prop(mesh, "use_remesh_preserve_sculpt_face_sets")
+
+ col = layout.column(heading="Preserve")
+ col.prop(mesh, "use_remesh_preserve_volume", text="Volume")
+ col.prop(mesh, "use_remesh_preserve_paint_mask", text="Paint Mask")
+ col.prop(mesh, "use_remesh_preserve_sculpt_face_sets", text="Face Sets")
col.operator("object.voxel_remesh", text="Voxel Remesh")
else:
col.operator("object.quadriflow_remesh", text="QuadriFlow Remesh")
@@ -515,12 +510,12 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
else:
col.operator("mesh.customdata_custom_splitnormals_add", icon='ADD')
- col = layout.column()
+ col = layout.column(heading="Store")
col.enabled = obj is not None and obj.mode != 'EDIT'
- col.prop(me, "use_customdata_vertex_bevel")
- col.prop(me, "use_customdata_edge_bevel")
- col.prop(me, "use_customdata_edge_crease")
+ col.prop(me, "use_customdata_vertex_bevel", text="Vertex Bevel Weight")
+ col.prop(me, "use_customdata_edge_bevel", text="Edge Bevel Weight")
+ col.prop(me, "use_customdata_edge_crease", text="Edge Crease")
class DATA_PT_custom_props_mesh(MeshButtonsPanel, PropertyPanel, Panel):
@@ -544,7 +539,6 @@ classes = (
DATA_PT_vertex_colors,
DATA_PT_face_maps,
DATA_PT_normals,
- DATA_PT_normals_auto_smooth,
DATA_PT_texture_space,
DATA_PT_remesh,
DATA_PT_customdata,
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index b9fc7431a9a..6e6bcd81cdc 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -686,8 +686,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
split = layout.split()
col = split.column()
col.prop(md, "levels", text="Preview")
- # TODO(sergey): Expose it again after T58473 is solved.
- # col.prop(md, "sculpt_levels", text="Sculpt")
+ col.prop(md, "sculpt_levels", text="Sculpt")
col.prop(md, "render_levels", text="Render")
row = col.row()
@@ -697,10 +696,20 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = split.column()
col.enabled = ob.mode != 'EDIT'
- col.operator("object.multires_subdivide", text="Subdivide")
+ op = col.operator("object.multires_subdivide", text="Subdivide")
+ op.mode = 'CATMULL_CLARK'
+
+ op = col.operator("object.multires_subdivide", text="Subdivide Simple")
+ op.mode = 'SIMPLE'
+
+ op = col.operator("object.multires_subdivide", text="Subdivide Linear")
+ op.mode = 'LINEAR'
+
col.operator("object.multires_higher_levels_delete", text="Delete Higher")
+ col.operator("object.multires_unsubdivide", text="Unsubdivide")
col.operator("object.multires_reshape", text="Reshape")
col.operator("object.multires_base_apply", text="Apply Base")
+ col.operator("object.multires_rebuild_subdiv", text="Rebuild Subdivisions")
col.prop(md, "uv_smooth", text="")
col.prop(md, "show_only_control_edges")
col.prop(md, "use_creases")
@@ -1341,7 +1350,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
if md.mode == 'VOXEL':
layout.prop(md, "voxel_size")
layout.prop(md, "adaptivity")
- else:
+ else:
row.prop(md, "octree_depth")
row.prop(md, "scale")
@@ -1976,6 +1985,27 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
self.gpencil_masking(layout, ob, md, True, True)
+ def GP_TEXTURE(self, layout, ob, md):
+ col = layout.column()
+
+ col.prop(md, "mode")
+ if md.mode in {'STROKE', 'STROKE_AND_FILL'}:
+ col.label(text="Stroke Texture:")
+ col.prop(md, "fit_method")
+ col.prop(md, "uv_offset")
+ col.prop(md, "uv_scale")
+
+ if md.mode == 'STROKE_AND_FILL':
+ col.separator()
+
+ if md.mode in {'FILL', 'STROKE_AND_FILL'}:
+ col.label(text="Fill Texture:")
+ col.prop(md, "fill_rotation", text="Rotation")
+ col.prop(md, "fill_offset", text="Location")
+ col.prop(md, "fill_scale", text="Scale")
+
+ self.gpencil_masking(layout, ob, md, True)
+
def GP_TINT(self, layout, ob, md):
layout.row().prop(md, "tint_type", expand=True)
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 5647f35383a..fea4406cb8c 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -361,6 +361,35 @@ class GPENCIL_MT_layer_active(Menu):
layout.operator("gpencil.layer_add", text="New Layer", icon='ADD')
+class GPENCIL_MT_material_active(Menu):
+ bl_label = "Change Active Material"
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.active_object
+ tool_settings = context.scene.tool_settings
+ mode = tool_settings.gpencil_paint.color_mode
+ if mode != 'MATERIAL':
+ return False
+
+ if ob is None or len(ob.material_slots) == 0:
+ return False
+
+ return True
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ ob = context.active_object
+ mat_active = ob.active_material
+
+ for slot in ob.material_slots:
+ mat = slot.material
+ if mat:
+ icon = mat.id_data.preview.icon_id
+ layout.operator("gpencil.material_set", text=mat.name, icon_value=icon).slot = mat.name
+
+
class GPENCIL_MT_gpencil_draw_delete(Menu):
bl_label = "Delete"
@@ -520,7 +549,7 @@ class AnnotationOnionSkin:
if gpl is None:
return False
- return True
+ return True
def draw_header(self, context):
gpl = context.active_annotation_layer
@@ -632,8 +661,8 @@ class GreasePencilMaterialsPanel:
if ob.data.use_stroke_edit_mode:
row = layout.row(align=True)
row.operator("gpencil.stroke_change_color", text="Assign")
- row.operator("gpencil.select_material", text="Select").deselect = False
- row.operator("gpencil.select_material", text="Deselect").deselect = True
+ row.operator("gpencil.material_select", text="Select").deselect = False
+ row.operator("gpencil.material_select", text="Deselect").deselect = True
# stroke color
ma = None
if is_view3d and brush is not None:
@@ -931,6 +960,7 @@ classes = (
GPENCIL_MT_cleanup,
GPENCIL_MT_move_to_layer,
GPENCIL_MT_layer_active,
+ GPENCIL_MT_material_active,
GPENCIL_MT_gpencil_draw_delete,
GPENCIL_MT_layer_mask_menu,
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index ab70c4c25c0..6aaec9940e8 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -172,10 +172,11 @@ class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel):
layout.prop(mat, "use_nodes", icon='NODETREE')
layout.separator()
+ layout.use_property_split = True
+
if mat.use_nodes:
panel_node_draw(layout, mat.node_tree, 'OUTPUT_MATERIAL', "Surface")
else:
- layout.use_property_split = True
layout.prop(mat, "diffuse_color", text="Base Color")
layout.prop(mat, "metallic")
layout.prop(mat, "specular_intensity", text="Specular")
@@ -197,6 +198,8 @@ class EEVEE_MATERIAL_PT_volume(MaterialButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
mat = context.material
panel_node_draw(layout, mat.node_tree, 'OUTPUT_MATERIAL', "Volume")
diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py
index a805b965af2..8ce53ed30eb 100644
--- a/release/scripts/startup/bl_ui/properties_object.py
+++ b/release/scripts/startup/bl_ui/properties_object.py
@@ -212,7 +212,6 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
layout = self.layout
layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
obj = context.object
obj_type = obj.type
@@ -222,35 +221,22 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
is_dupli = (obj.instance_type != 'NONE')
is_gpencil = (obj_type == 'GPENCIL')
- col = flow.column()
+ col = layout.column(heading="Show")
col.prop(obj, "show_name", text="Name")
-
- col = flow.column()
col.prop(obj, "show_axis", text="Axis")
# Makes no sense for cameras, armatures, etc.!
# but these settings do apply to dupli instances
if is_geometry or is_dupli:
- col = flow.column()
col.prop(obj, "show_wire", text="Wireframe")
if obj_type == 'MESH' or is_dupli:
- col = flow.column()
col.prop(obj, "show_all_edges", text="All Edges")
-
- col = flow.column()
if is_geometry:
col.prop(obj, "show_texture_space", text="Texture Space")
- col = flow.column()
col.prop(obj.display, "show_shadows", text="Shadow")
-
- col = flow.column()
col.prop(obj, "show_in_front", text="In Front")
# if obj_type == 'MESH' or is_empty_image:
# col.prop(obj, "show_transparent", text="Transparency")
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
if is_wire:
# wire objects only use the max. display type for duplis
col.active = is_dupli
@@ -258,28 +244,17 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
if is_geometry or is_dupli or is_empty_image or is_gpencil:
# Only useful with object having faces/materials...
- col = flow.column()
col.prop(obj, "color")
-
-class OBJECT_PT_display_bounds(ObjectButtonsPanel, Panel):
- bl_label = "Bounds"
- bl_parent_id = "OBJECT_PT_display"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, context):
-
- obj = context.object
-
- self.layout.prop(obj, "show_bounds", text="")
-
- def draw(self, context):
- layout = self.layout
- obj = context.object
- layout.use_property_split = True
-
- layout.active = obj.show_bounds or (obj.display_type == 'BOUNDS')
- layout.prop(obj, "display_bounds_type", text="Shape")
+ col = layout.column(align=False, heading="Bounds")
+ col.use_property_decorate = False
+ row = col.row(align=True)
+ sub = row.row(align=True)
+ sub.prop(obj, "show_bounds", text="")
+ sub = sub.row(align=True)
+ sub.active = obj.show_bounds or (obj.display_type == 'BOUNDS')
+ sub.prop(obj, "display_bounds_type", text="")
+ row.prop_decorator(obj, "display_bounds_type")
class OBJECT_PT_instancing(ObjectButtonsPanel, Panel):
@@ -295,7 +270,6 @@ class OBJECT_PT_instancing(ObjectButtonsPanel, Panel):
row.prop(ob, "instance_type", expand=True)
layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
if ob.instance_type == 'VERTS':
layout.prop(ob, "use_instance_vertices_rotation", text="Align to Vertex Normal")
@@ -305,9 +279,9 @@ class OBJECT_PT_instancing(ObjectButtonsPanel, Panel):
col.prop(ob, "instance_collection", text="Collection")
if ob.instance_type != 'NONE' or ob.particle_systems:
- col = flow.column(align=True)
- col.prop(ob, "show_instancer_for_viewport")
- col.prop(ob, "show_instancer_for_render")
+ col = layout.column(heading="Show Instancer", align=True)
+ col.prop(ob, "show_instancer_for_viewport", text="Viewport")
+ col.prop(ob, "show_instancer_for_render", text="Render")
class OBJECT_PT_instancing_size(ObjectButtonsPanel, Panel):
@@ -385,19 +359,17 @@ class OBJECT_PT_visibility(ObjectButtonsPanel, Panel):
layout = self.layout
layout.use_property_split = True
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
layout = self.layout
ob = context.object
- col = flow.column()
- col.prop(ob, "hide_viewport", text="Show in Viewports", toggle=False, invert_checkbox=True)
- col = flow.column()
- col.prop(ob, "hide_render", text="Show in Renders", toggle=False, invert_checkbox=True)
- col = flow.column()
- col.prop(ob, "hide_select", text="Selectable", toggle=False, invert_checkbox=True)
+ layout.prop(ob, "hide_select", text="Selectable", toggle=False, invert_checkbox=True)
+
+ col = layout.column(heading="Show in")
+ col.prop(ob, "hide_viewport", text="Viewports", toggle=False, invert_checkbox=True)
+ col.prop(ob, "hide_render", text="Renders", toggle=False, invert_checkbox=True)
if context.object.type == 'GPENCIL':
- col = flow.column()
+ col = layout.column(heading="Grease Pencil")
col.prop(ob, "use_grease_pencil_lights", toggle=False)
@@ -419,7 +391,6 @@ classes = (
OBJECT_PT_motion_paths,
OBJECT_PT_motion_paths_display,
OBJECT_PT_display,
- OBJECT_PT_display_bounds,
OBJECT_PT_visibility,
OBJECT_PT_custom_props,
)
diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py
index 748961bb40f..e859798c085 100644
--- a/release/scripts/startup/bl_ui/properties_output.py
+++ b/release/scripts/startup/bl_ui/properties_output.py
@@ -94,14 +94,14 @@ class RENDER_PT_dimensions(RenderOutputButtonsPanel, Panel):
return args
@staticmethod
- def draw_framerate(layout, sub, rd):
+ def draw_framerate(layout, rd):
if RENDER_PT_dimensions._preset_class is None:
RENDER_PT_dimensions._preset_class = bpy.types.RENDER_MT_framerate_presets
args = rd.fps, rd.fps_base, RENDER_PT_dimensions._preset_class.bl_label
fps_label_text, show_framerate = RENDER_PT_dimensions._draw_framerate_label(*args)
- sub.menu("RENDER_MT_framerate_presets", text=fps_label_text)
+ layout.menu("RENDER_MT_framerate_presets", text=fps_label_text)
if show_framerate:
col = layout.column(align=True)
@@ -136,10 +136,8 @@ class RENDER_PT_dimensions(RenderOutputButtonsPanel, Panel):
col.prop(scene, "frame_end", text="End")
col.prop(scene, "frame_step", text="Step")
- col = layout.split()
- col.alignment = 'RIGHT'
- col.label(text="Frame Rate")
- self.draw_framerate(layout, col, rd)
+ col = layout.column(heading="Frame Rate")
+ self.draw_framerate(col, rd)
class RENDER_PT_frame_remapping(RenderOutputButtonsPanel, Panel):
@@ -171,10 +169,8 @@ class RENDER_PT_post_processing(RenderOutputButtonsPanel, Panel):
rd = context.scene.render
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- col = flow.column()
+ col = layout.column(heading="Pipeline")
col.prop(rd, "use_compositing")
- col = flow.column()
col.prop(rd, "use_sequencer")
layout.prop(rd, "dither_intensity", text="Dither", slider=True)
@@ -192,44 +188,23 @@ class RENDER_PT_stamp(RenderOutputButtonsPanel, Panel):
rd = context.scene.render
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ if rd.use_sequencer:
+ layout.prop(rd, "metadata_input")
- col = flow.column()
+ col = layout.column(heading="Include")
col.prop(rd, "use_stamp_date", text="Date")
- col = flow.column()
col.prop(rd, "use_stamp_time", text="Time")
-
- col = flow.column()
col.prop(rd, "use_stamp_render_time", text="Render Time")
- col = flow.column()
col.prop(rd, "use_stamp_frame", text="Frame")
- col = flow.column()
col.prop(rd, "use_stamp_frame_range", text="Frame Range")
- col = flow.column()
col.prop(rd, "use_stamp_memory", text="Memory")
- col = flow.column()
col.prop(rd, "use_stamp_hostname", text="Hostname")
-
- col = flow.column()
col.prop(rd, "use_stamp_camera", text="Camera")
- col = flow.column()
col.prop(rd, "use_stamp_lens", text="Lens")
-
- col = flow.column()
col.prop(rd, "use_stamp_scene", text="Scene")
- col = flow.column()
col.prop(rd, "use_stamp_marker", text="Marker")
-
- col = flow.column()
col.prop(rd, "use_stamp_filename", text="Filename")
- col = flow.column()
- col.prop(rd, "use_stamp_sequencer_strip", text="Strip Name")
-
- if rd.use_sequencer:
- col = flow.column()
- col.prop(rd, "use_stamp_strip_meta", text="Use Strip Metadata")
-
class RENDER_PT_stamp_note(RenderOutputButtonsPanel, Panel):
bl_label = "Note"
@@ -293,21 +268,17 @@ class RENDER_PT_output(RenderOutputButtonsPanel, Panel):
layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
- col.active = not rd.is_movie_format
- col.prop(rd, "use_overwrite")
- col = flow.column()
- col.active = not rd.is_movie_format
- col.prop(rd, "use_placeholder")
- col = flow.column()
+ col = layout.column(heading="Saving")
col.prop(rd, "use_file_extension")
- col = flow.column()
col.prop(rd, "use_render_cache")
layout.template_image_settings(image_settings, color_management=False)
+ if not rd.is_movie_format:
+ col = layout.column(heading="Image Sequence")
+ col.prop(rd, "use_overwrite")
+ col.prop(rd, "use_placeholder")
+
class RENDER_PT_output_views(RenderOutputButtonsPanel, Panel):
bl_label = "Views"
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 6be1aa40bf2..6de1b38a615 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -587,10 +587,12 @@ def brush_settings(layout, context, brush, popover=False):
slider=True,
)
- layout.prop(brush, "use_plane_trim", text="Plane Trim")
- row = layout.row()
- row.active = brush.use_plane_trim
- row.prop(brush, "plane_trim", slider=True, text="Distance")
+ row = layout.row(heading="Plane Trim")
+ row.prop(brush, "use_plane_trim", text="")
+ sub = row.row()
+ sub.active = brush.use_plane_trim
+ sub.prop(brush, "plane_trim", slider=True, text="")
+
layout.separator()
# height
@@ -808,23 +810,27 @@ def brush_settings_advanced(layout, context, brush, popover=False):
use_accumulate = capabilities.has_accumulate
use_frontface = True
+ col = layout.column(heading="Auto-Masking", align=True)
+
# topology automasking
- layout.prop(brush, "use_automasking_topology")
+ col.prop(brush, "use_automasking_topology", text="Topology")
# face masks automasking
- layout.prop(brush, "use_automasking_face_sets")
-
+ col.prop(brush, "use_automasking_face_sets", text="Face Sets")
+
# boundary edges/face sets automasking
- layout.prop(brush, "use_automasking_boundary_edges")
- layout.prop(brush, "use_automasking_boundary_face_sets")
- layout.prop(brush, "automasking_boundary_edges_propagation_steps")
+ col.prop(brush, "use_automasking_boundary_edges", text="Mesh Boundary")
+ col.prop(brush, "use_automasking_boundary_face_sets", text="Face Sets")
+ col.prop(brush, "automasking_boundary_edges_propagation_steps")
+ layout.separator()
# sculpt plane settings
if capabilities.has_sculpt_plane:
layout.prop(brush, "sculpt_plane")
- layout.prop(brush, "use_original_normal")
- layout.prop(brush, "use_original_plane")
+ col = layout.column(heading="Use Original", align=True)
+ col.prop(brush, "use_original_normal", text="Normal")
+ col.prop(brush, "use_original_plane", text="Plane")
layout.separator()
# 3D and 2D Texture Paint.
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index 479782f1e3b..0cd99efcca9 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -310,8 +310,10 @@ def basic_force_field_settings_ui(self, field):
else:
col.prop(field, "flow")
- col.prop(field, "apply_to_location", text="Affect Location")
- col.prop(field, "apply_to_rotation", text="Affect Rotation")
+ sub = col.column(heading="Affect")
+
+ sub.prop(field, "apply_to_location", text="Location")
+ sub.prop(field, "apply_to_rotation", text="Rotation")
col = flow.column()
sub = col.column(align=True)
@@ -336,26 +338,29 @@ def basic_force_field_falloff_ui(self, field):
if not field or field.type == 'NONE':
return
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- col = flow.column()
+ col = layout.column()
col.prop(field, "z_direction")
col.prop(field, "falloff_power", text="Power")
- col = flow.column()
- col.prop(field, "use_min_distance", text="Use Minimum")
-
- sub = col.column(align=True)
+ col = layout.column(align=False, heading="Min Distance")
+ col.use_property_decorate = False
+ row = col.row(align=True)
+ sub = row.row(align=True)
+ sub.prop(field, "use_min_distance", text="")
+ sub = sub.row(align=True)
sub.active = field.use_min_distance
- sub.prop(field, "distance_min", text="Min Distance")
-
- col = flow.column()
- col.prop(field, "use_max_distance", text="Use Maximum")
-
- sub = col.column(align=True)
+ sub.prop(field, "distance_min", text="")
+ row.prop_decorator(field, "distance_min")
+
+ col = layout.column(align=False, heading="Max Distance")
+ col.use_property_decorate = False
+ row = col.row(align=True)
+ sub = row.row(align=True)
+ sub.prop(field, "use_max_distance", text="")
+ sub = sub.row(align=True)
sub.active = field.use_max_distance
- sub.prop(field, "distance_max", text="Max Distance")
-
+ sub.prop(field, "distance_max", text="")
+ row.prop_decorator(field, "distance_max")
classes = (
PHYSICS_PT_add,
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index fd4859f3620..2d13aed617c 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -475,33 +475,21 @@ class RENDER_PT_eevee_film(RenderButtonsPanel, Panel):
scene = context.scene
rd = scene.render
+ props = scene.eevee
col = layout.column()
col.prop(rd, "filter_size")
col.prop(rd, "film_transparent", text="Transparent")
-
-class RENDER_PT_eevee_film_overscan(RenderButtonsPanel, Panel):
- bl_label = "Overscan"
- bl_parent_id = "RENDER_PT_eevee_film"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_EEVEE'}
-
- def draw_header(self, context):
-
- scene = context.scene
- props = scene.eevee
-
- self.layout.prop(props, "use_overscan", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- scene = context.scene
- props = scene.eevee
-
- layout.active = props.use_overscan
- layout.prop(props, "overscan_size", text="Size")
+ col = layout.column(align=False, heading="Overscan")
+ col.use_property_decorate = False
+ row = col.row(align=True)
+ sub = row.row(align=True)
+ sub.prop(props, "use_overscan", text="")
+ sub = sub.row(align=True)
+ sub.active = props.use_overscan
+ sub.prop(props, "overscan_size", text="")
+ row.prop_decorator(props, "overscan_size")
class RENDER_PT_eevee_hair(RenderButtonsPanel, Panel):
@@ -696,7 +684,6 @@ classes = (
RENDER_PT_eevee_indirect_lighting,
RENDER_PT_eevee_indirect_lighting_display,
RENDER_PT_eevee_film,
- RENDER_PT_eevee_film_overscan,
RENDER_PT_opengl_sampling,
RENDER_PT_opengl_lighting,
RENDER_PT_opengl_color,
diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py
index 40a630ff834..5af8bc2aaa7 100644
--- a/release/scripts/startup/bl_ui/properties_texture.py
+++ b/release/scripts/startup/bl_ui/properties_texture.py
@@ -163,6 +163,8 @@ class TEXTURE_PT_node(TextureButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
node = context.texture_node
ntree = node.id_data
layout.template_node_view(ntree, node, None)
diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py
index 5fe06ebbb6e..3645f0dc2f2 100644
--- a/release/scripts/startup/bl_ui/properties_view_layer.py
+++ b/release/scripts/startup/bl_ui/properties_view_layer.py
@@ -40,17 +40,12 @@ class VIEWLAYER_PT_layer(ViewLayerButtonsPanel, Panel):
layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- layout.use_property_split = True
-
scene = context.scene
rd = scene.render
layer = context.view_layer
- col = flow.column()
+ col = layout.column()
col.prop(layer, "use", text="Use for Rendering")
- col = flow.column()
col.prop(rd, "use_single_layer", text="Render Single Layer")
@@ -77,14 +72,10 @@ class VIEWLAYER_PT_eevee_layer_passes_data(ViewLayerButtonsPanel, Panel):
rd = scene.render
view_layer = context.view_layer
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- col = flow.column()
+ col = layout.column()
col.prop(view_layer, "use_pass_combined")
- col = flow.column()
col.prop(view_layer, "use_pass_z")
- col = flow.column()
col.prop(view_layer, "use_pass_mist")
- col = flow.column()
col.prop(view_layer, "use_pass_normal")
@@ -104,29 +95,19 @@ class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel):
scene = context.scene
scene_eevee = scene.eevee
- split = layout.split(factor=0.35)
- split.use_property_split = False
- split.label(text="Diffuse")
- row = split.row(align=True)
- row.prop(view_layer, "use_pass_diffuse_direct", text="Light", toggle=True)
- row.prop(view_layer, "use_pass_diffuse_color", text="Color", toggle=True)
-
- split = layout.split(factor=0.35)
- split.use_property_split = False
- split.label(text="Specular")
- row = split.row(align=True)
- row.prop(view_layer, "use_pass_glossy_direct", text="Light", toggle=True)
- row.prop(view_layer, "use_pass_glossy_color", text="Color", toggle=True)
-
- split = layout.split(factor=0.35)
- split.use_property_split = False
- split.label(text="Volume")
- row = split.row(align=True)
- row.prop(view_layer_eevee, "use_pass_volume_transmittance", text="Transmittance", toggle=True)
- row.prop(view_layer_eevee, "use_pass_volume_scatter", text="Scatter", toggle=True)
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = layout.column(align=True)
+ col = layout.column(heading="Diffuse", align=True)
+ col.prop(view_layer, "use_pass_diffuse_direct", text="Light")
+ col.prop(view_layer, "use_pass_diffuse_color", text="Color")
+
+ col = layout.column(heading="Specular", align=True)
+ col.prop(view_layer, "use_pass_glossy_direct", text="Light")
+ col.prop(view_layer, "use_pass_glossy_color", text="Color")
+
+ col = layout.column(heading="Volume", align=True)
+ col.prop(view_layer_eevee, "use_pass_volume_transmittance", text="Transmittance")
+ col.prop(view_layer_eevee, "use_pass_volume_scatter", text="Scatter")
+
+ col = layout.column(heading="Other", align=True)
col.prop(view_layer, "use_pass_emit", text="Emission")
col.prop(view_layer, "use_pass_environment")
col.prop(view_layer, "use_pass_shadow")
@@ -146,14 +127,12 @@ class VIEWLAYER_PT_eevee_layer_passes_effects(ViewLayerButtonsPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
view_layer = context.view_layer
view_layer_eevee = view_layer.eevee
scene = context.scene
scene_eevee = scene.eevee
- col = flow.column()
+ col = layout.column()
col.prop(view_layer_eevee, "use_pass_bloom", text="Bloom")
col.active = scene_eevee.use_bloom
diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py
index 705be66ecc1..6f00e521e58 100644
--- a/release/scripts/startup/bl_ui/properties_world.py
+++ b/release/scripts/startup/bl_ui/properties_world.py
@@ -105,6 +105,8 @@ class EEVEE_WORLD_PT_surface(WorldButtonsPanel, Panel):
layout.prop(world, "use_nodes", icon='NODETREE')
layout.separator()
+ layout.use_property_split = True
+
if world.use_nodes:
ntree = world.node_tree
node = ntree.get_output_node('EEVEE')
@@ -139,6 +141,8 @@ class EEVEE_WORLD_PT_volume(WorldButtonsPanel, Panel):
ntree = world.node_tree
node = ntree.get_output_node('EEVEE')
+ layout.use_property_split = True
+
if node:
input = find_node_input(node, 'Volume')
if input:
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index f93629a4f03..5b6cc6609e0 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -918,6 +918,10 @@ class CLIP_PT_tracking_lens(Panel):
col = layout.column(align=True)
col.prop(camera, "division_k1")
col.prop(camera, "division_k2")
+ elif camera.distortion_model == 'NUKE':
+ col = layout.column(align=True)
+ col.prop(camera, "nuke_k1")
+ col.prop(camera, "nuke_k2")
class CLIP_PT_marker(CLIP_PT_tracking_panel, Panel):
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index 3bf5bbf7b46..53fc812a619 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -66,8 +66,9 @@ class FILEBROWSER_PT_display(Panel):
if params.display_type == 'THUMBNAIL':
layout.prop(params, "display_size", text="Size")
else:
- layout.prop(params, "show_details_size", text="Size")
- layout.prop(params, "show_details_datetime", text="Date")
+ col = layout.column(heading="Columns", align=True)
+ col.prop(params, "show_details_size", text="Size")
+ col.prop(params, "show_details_datetime", text="Date")
layout.prop(params, "recursion_level", text="Recursions")
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 4506307067e..324c1238db3 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -384,6 +384,10 @@ class IMAGE_MT_uvs(Menu):
layout.separator()
+ layout.operator("uv.reset")
+
+ layout.separator()
+
class IMAGE_MT_uvs_select_mode(Menu):
bl_label = "UV Select Mode"
@@ -955,6 +959,7 @@ class IMAGE_PT_view_display_uv_edit_overlays(Panel):
col = layout.column()
col.prop(uvedit, "show_smooth_edges", text="Smooth")
col.prop(uvedit, "show_modified_edges", text="Modified")
+ col.prop(uvedit, "uv_opacity")
class IMAGE_PT_view_display_uv_edit_overlays_stretch(Panel):
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index bdda0ebbe9a..b5926692324 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -151,6 +151,14 @@ class NODE_HT_header(Header):
if snode_id:
layout.prop(snode_id, "use_nodes")
+ elif snode.tree_type == 'SimulationNodeTree':
+ row = layout.row(align=True)
+ row.prop(snode, "simulation", text="")
+ row.operator("simulation.new", text="", icon='ADD')
+ simulation = snode.simulation
+ if simulation:
+ row.prop(snode.simulation, "use_fake_user", text="")
+
else:
# Custom node tree is edited as independent ID block
NODE_MT_editor_menus.draw_collapsible(context, layout)
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index a74d9cc9547..ee8015df273 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -212,8 +212,8 @@ class OUTLINER_MT_collection(Menu):
layout.separator()
- layout.operator("outliner.collection_delete", text="Delete", icon='X').hierarchy = False
- layout.operator("outliner.collection_delete", text="Delete Hierarchy").hierarchy = True
+ layout.operator("outliner.delete", text="Delete", icon='X')
+ layout.operator("outliner.collection_hierarchy_delete")
layout.separator()
@@ -278,7 +278,7 @@ class OUTLINER_MT_object(Menu):
layout.separator()
- layout.operator("outliner.object_operation", text="Delete", icon='X').type = 'DELETE'
+ layout.operator("outliner.delete", text="Delete", icon='X')
if space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection:
layout.operator("outliner.object_operation", text="Delete Hierarchy").type = 'DELETE_HIERARCHY'
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index c0a2b8a1230..e1f675871ef 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -29,6 +29,7 @@ from bpy.app.translations import (
)
from bl_ui.properties_grease_pencil_common import (
AnnotationDataPanel,
+ AnnotationOnionSkin,
)
from bl_ui.space_toolsystem_common import (
ToolActivePanelHelper,
@@ -1138,6 +1139,8 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
col = layout.column(align=True)
if strip_type == 'SPEED':
col.prop(strip, "multiply_speed")
+ col.prop(strip, "frame_interpolation_mode")
+
elif strip_type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}:
col.prop(strip, "use_default_fade", text="Default fade")
if not strip.use_default_fade:
@@ -1687,18 +1690,15 @@ class SEQUENCER_PT_adjust_transform(SequencerButtonsPanel, Panel):
layout = self.layout
strip = act_strip(context)
- layout.active = not strip.mute
-
- split = layout.split()
+ layout.use_property_split = True
+ layout.use_property_decorate = False
- col = split.column()
- col.alignment = 'RIGHT'
- col.label(text="Mirror")
+ layout.active = not strip.mute
- col = split.column()
- row = col.row(align=True)
- row.prop(strip, "use_flip_x", text="X", toggle=True)
- row.prop(strip, "use_flip_y", text="Y", toggle=True)
+ row = layout.row(heading="Mirror")
+ sub = row.row(align=True)
+ sub.prop(strip, "use_flip_x", text="X", toggle=True)
+ sub.prop(strip, "use_flip_y", text="Y", toggle=True)
class SEQUENCER_PT_adjust_video(SequencerButtonsPanel, Panel):
@@ -1802,12 +1802,12 @@ class SEQUENCER_PT_cache_settings(SequencerButtonsPanel, Panel):
ed = context.scene.sequence_editor
- col = layout.column()
+ col = layout.column(heading="Cache", align=True)
- col.prop(ed, "use_cache_raw")
- col.prop(ed, "use_cache_preprocessed")
- col.prop(ed, "use_cache_composite")
- col.prop(ed, "use_cache_final")
+ col.prop(ed, "use_cache_raw", text="Raw")
+ col.prop(ed, "use_cache_preprocessed", text="Pre-Processed")
+ col.prop(ed, "use_cache_composite", text="Composite")
+ col.prop(ed, "use_cache_final", text="Final")
col.separator()
col.prop(ed, "recycle_max_cost")
@@ -1871,21 +1871,19 @@ class SEQUENCER_PT_strip_proxy(SequencerButtonsPanel, Panel):
flow = layout.column_flow()
if ed.proxy_storage == 'PER_STRIP':
- flow.prop(proxy, "use_proxy_custom_directory")
- flow.prop(proxy, "use_proxy_custom_file")
-
+ col = layout.column(heading="Custom Proxy")
+ col.prop(proxy, "use_proxy_custom_directory", text="Directory")
if proxy.use_proxy_custom_directory and not proxy.use_proxy_custom_file:
- flow.prop(proxy, "directory")
+ col.prop(proxy, "directory")
+ col.prop(proxy, "use_proxy_custom_file", text="File")
if proxy.use_proxy_custom_file:
- flow.prop(proxy, "filepath")
+ col.prop(proxy, "filepath")
- box = layout.box()
- row = box.row(align=True)
- row.prop(strip.proxy, "build_25")
- row.prop(strip.proxy, "build_75")
- row = box.row(align=True)
- row.prop(strip.proxy, "build_50")
- row.prop(strip.proxy, "build_100")
+ row = layout.row(heading="Resolutions", align=True)
+ row.prop(strip.proxy, "build_25", toggle=True)
+ row.prop(strip.proxy, "build_75", toggle=True)
+ row.prop(strip.proxy, "build_50", toggle=True)
+ row.prop(strip.proxy, "build_100", toggle=True)
layout.use_property_split = True
layout.use_property_decorate = False
@@ -1926,10 +1924,10 @@ class SEQUENCER_PT_strip_cache(SequencerButtonsPanel, Panel):
strip = act_strip(context)
layout.active = strip.override_cache_settings
- col = layout.column()
- col.prop(strip, "use_cache_raw")
- col.prop(strip, "use_cache_preprocessed")
- col.prop(strip, "use_cache_composite")
+ col = layout.column(heading="Cache")
+ col.prop(strip, "use_cache_raw", text="Raw")
+ col.prop(strip, "use_cache_preprocessed", text="Pre-Processed")
+ col.prop(strip, "use_cache_composite", text="Composite")
class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel):
@@ -2087,10 +2085,12 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
box = layout.box()
row = box.row()
+ row.use_property_decorate = False
row.prop(mod, "show_expanded", text="", emboss=False)
row.prop(mod, "name", text="")
row.prop(mod, "mute", text="")
+ row.use_property_decorate = True
sub = row.row(align=True)
props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_UP')
@@ -2162,6 +2162,33 @@ class SEQUENCER_PT_annotation(AnnotationDataPanel, SequencerButtonsPanel_Output,
# But, it should only show up when there are images in the preview region
+class SEQUENCER_PT_annotation_onion(AnnotationOnionSkin, SequencerButtonsPanel_Output, Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "View"
+
+ @staticmethod
+ def has_preview(context):
+ st = context.space_data
+ return st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}
+
+ @classmethod
+ def poll(cls, context):
+ if context.annotation_data_owner is None:
+ return False
+ elif type(context.annotation_data_owner) is bpy.types.Object:
+ return False
+ else:
+ gpl = context.active_annotation_layer
+ if gpl is None:
+ return False
+
+ return cls.has_preview(context)
+
+ # NOTE: this is just a wrapper around the generic GP Panel
+ # But, it should only show up when there are images in the preview region
+
+
class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
_context_path = "scene.sequence_editor.active_strip"
@@ -2235,6 +2262,7 @@ classes = (
SEQUENCER_PT_view_safe_areas_center_cut,
SEQUENCER_PT_annotation,
+ SEQUENCER_PT_annotation_onion,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py
index b7c5dcd5437..f6f22ad464f 100644
--- a/release/scripts/startup/bl_ui/space_text.py
+++ b/release/scripts/startup/bl_ui/space_text.py
@@ -129,18 +129,21 @@ class TEXT_PT_properties(Panel):
layout.use_property_decorate = False
st = context.space_data
- flow = layout.column_flow()
if not st.text:
- flow.active = False
- row = flow.row(align=True)
+ layout.active = False
+
st = context.space_data
- row.prop(st, "show_margin", text="Margin")
- rowsub = row.row()
- rowsub.active = st.show_margin
- rowsub.prop(st, "margin_column", text="")
- flow.prop(st, "font_size")
- flow.prop(st, "tab_width")
+ col = layout.column(align=False, heading="Margin")
+ row = col.row(align=True)
+ sub = row.row(align=True)
+ sub.prop(st, "show_margin", text="")
+ sub = sub.row(align=True)
+ sub.active = st.show_margin
+ sub.prop(st, "margin_column", text="")
+
+ layout.prop(st, "font_size")
+ layout.prop(st, "tab_width")
text = st.text
if text:
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 3c9355d0017..8638f1a2a27 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -628,9 +628,10 @@ class _defs_edit_mesh:
layout.prop(props, "vertex_only")
layout.prop(props, "clamp_overlap")
layout.prop(props, "loop_slide")
- layout.prop(props, "mark_seam")
- layout.prop(props, "mark_sharp")
layout.prop(props, "harden_normals")
+ col = layout.column(heading="Mark")
+ col.prop(props, "mark_seam", text="Seam")
+ col.prop(props, "mark_sharp", text="Sharp")
layout.prop(props, "material")
@@ -671,6 +672,19 @@ class _defs_edit_mesh:
)
@ToolDef.from_fn
+ def extrude_dissolve_and_intersect():
+ return dict(
+ idname="builtin.extrude_dissolve_and_intersect",
+ label="Extrude Dissolve and Intersect",
+ description=(
+ "Extrude, dissolves edges whose faces form a flat surface and intersect new edges"
+ ),
+ icon="none",
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
+ keymap=(),
+ )
+
+ @ToolDef.from_fn
def extrude_normals():
def draw_settings(_context, layout, tool):
props = tool.operator_properties("mesh.extrude_region_shrink_fatten")
@@ -2114,6 +2128,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
(
_defs_edit_mesh.extrude,
+ _defs_edit_mesh.extrude_dissolve_and_intersect,
_defs_edit_mesh.extrude_normals,
_defs_edit_mesh.extrude_individual,
_defs_edit_mesh.extrude_cursor,
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index 1e6f03c2b0c..7a23eb9282c 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -580,6 +580,8 @@ class TOPBAR_MT_edit(Menu):
def draw(self, context):
layout = self.layout
+ show_developer = context.preferences.view.show_developer_ui
+
layout.operator("ed.undo")
layout.operator("ed.redo")
@@ -598,8 +600,9 @@ class TOPBAR_MT_edit(Menu):
layout.separator()
- layout.operator("wm.search_menu",
- text="Operator Search...", icon='VIEWZOOM')
+ layout.operator("wm.search_menu", text="Menu Search...", icon='VIEWZOOM')
+ if show_developer:
+ layout.operator("wm.search_operator", text="Operator Search...", icon='VIEWZOOM')
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 3d579053a97..bb68eeb4447 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -200,19 +200,16 @@ class USERPREF_PT_interface_display(InterfacePanel, CenterAlignMixIn, Panel):
prefs = context.preferences
view = prefs.view
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(view, "ui_scale", text="Resolution Scale")
- flow.prop(view, "ui_line_width", text="Line Width")
-
- layout.separator()
+ col = layout.column()
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ col.prop(view, "ui_scale", text="Resolution Scale")
+ col.prop(view, "ui_line_width", text="Line Width")
+ col.prop(view, "show_splash", text="Splash Screen")
+ col.prop(view, "show_developer_ui")
- flow.prop(view, "show_splash", text="Splash Screen")
- flow.prop(view, "show_tooltips")
- flow.prop(view, "show_tooltips_python")
- flow.prop(view, "show_developer_ui")
+ col = layout.column(heading="Tooltips")
+ col.prop(view, "show_tooltips")
+ col.prop(view, "show_tooltips_python")
class USERPREF_PT_interface_text(InterfacePanel, CenterAlignMixIn, Panel):
@@ -248,12 +245,11 @@ class USERPREF_PT_interface_translation(InterfacePanel, CenterAlignMixIn, Panel)
layout.prop(view, "language")
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
- flow.active = (bpy.app.translations.locale != 'en_US')
-
- flow.prop(view, "use_translate_tooltips", text="Tooltips")
- flow.prop(view, "use_translate_interface", text="Interface")
- flow.prop(view, "use_translate_new_dataname", text="New Data")
+ col = layout.column(heading="Affect")
+ col.active = (bpy.app.translations.locale != 'en_US')
+ col.prop(view, "use_translate_tooltips", text="Tooltips")
+ col.prop(view, "use_translate_interface", text="Interface")
+ col.prop(view, "use_translate_new_dataname", text="New Data")
class USERPREF_PT_interface_editors(InterfacePanel, CenterAlignMixIn, Panel):
@@ -264,14 +260,13 @@ class USERPREF_PT_interface_editors(InterfacePanel, CenterAlignMixIn, Panel):
view = prefs.view
system = prefs.system
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(system, "use_region_overlap")
- flow.prop(view, "show_layout_ui", text="Corner Splitting")
- flow.prop(view, "show_navigate_ui")
- flow.prop(view, "color_picker_type")
- flow.row().prop(view, "header_align")
- flow.prop(view, "factor_display_type")
+ col = layout.column()
+ col.prop(system, "use_region_overlap")
+ col.prop(view, "show_layout_ui", text="Corner Splitting")
+ col.prop(view, "show_navigate_ui")
+ col.prop(view, "color_picker_type")
+ col.row().prop(view, "header_align")
+ col.prop(view, "factor_display_type")
class USERPREF_PT_interface_temporary_windows(InterfacePanel, CenterAlignMixIn, Panel):
@@ -283,10 +278,9 @@ class USERPREF_PT_interface_temporary_windows(InterfacePanel, CenterAlignMixIn,
prefs = context.preferences
view = prefs.view
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(view, "render_display_type", text="Render in")
- flow.prop(view, "filebrowser_display_type", text="File Browser")
+ col = layout.column()
+ col.prop(view, "render_display_type", text="Render in")
+ col.prop(view, "filebrowser_display_type", text="File Browser")
class USERPREF_PT_interface_menus(InterfacePanel, Panel):
@@ -376,6 +370,8 @@ class USERPREF_PT_edit_objects_duplicate_data(EditingPanel, CenterAlignMixIn, Pa
prefs = context.preferences
edit = prefs.edit
+ layout.use_property_split = False
+
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
col = flow.column()
@@ -409,10 +405,9 @@ class USERPREF_PT_edit_cursor(EditingPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
edit = prefs.edit
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(edit, "use_mouse_depth_cursor")
- flow.prop(edit, "use_cursor_lock_adjust")
+ col = layout.column()
+ col.prop(edit, "use_mouse_depth_cursor")
+ col.prop(edit, "use_cursor_lock_adjust")
class USERPREF_PT_edit_gpencil(EditingPanel, CenterAlignMixIn, Panel):
@@ -423,10 +418,9 @@ class USERPREF_PT_edit_gpencil(EditingPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
edit = prefs.edit
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance")
- flow.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance")
+ col = layout.column(heading="Distance")
+ col.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan")
+ col.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean")
class USERPREF_PT_edit_annotations(EditingPanel, CenterAlignMixIn, Panel):
@@ -436,10 +430,9 @@ class USERPREF_PT_edit_annotations(EditingPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
edit = prefs.edit
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(edit, "grease_pencil_default_color", text="Default Color")
- flow.prop(edit, "grease_pencil_eraser_radius", text="Eraser Radius")
+ col = layout.column()
+ col.prop(edit, "grease_pencil_default_color", text="Default Color")
+ col.prop(edit, "grease_pencil_eraser_radius", text="Eraser Radius")
class USERPREF_PT_edit_weight_paint(EditingPanel, CenterAlignMixIn, Panel):
@@ -450,6 +443,8 @@ class USERPREF_PT_edit_weight_paint(EditingPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
view = prefs.view
+ layout.use_property_split = False
+
layout.prop(view, "use_weight_color_range", text="Use Custom Colors")
col = layout.column()
@@ -465,10 +460,9 @@ class USERPREF_PT_edit_misc(EditingPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
edit = prefs.edit
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(edit, "sculpt_paint_overlay_color", text="Sculpt Overlay Color")
- flow.prop(edit, "node_margin", text="Node Auto-offset Margin")
+ col = layout.column()
+ col.prop(edit, "sculpt_paint_overlay_color", text="Sculpt Overlay Color")
+ col.prop(edit, "node_margin", text="Node Auto-offset Margin")
# -----------------------------------------------------------------------------
@@ -488,20 +482,16 @@ class USERPREF_PT_animation_timeline(AnimationPanel, CenterAlignMixIn, Panel):
view = prefs.view
edit = prefs.edit
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
- flow.prop(edit, "use_negative_frames")
-
- layout.separator()
-
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ col = layout.column()
+ col.prop(edit, "use_negative_frames")
- flow.prop(view, "view2d_grid_spacing_min", text="Minimum Grid Spacing")
- flow.prop(view, "timecode_style")
- flow.prop(view, "view_frame_type")
+ col.prop(view, "view2d_grid_spacing_min", text="Minimum Grid Spacing")
+ col.prop(view, "timecode_style")
+ col.prop(view, "view_frame_type")
if view.view_frame_type == 'SECONDS':
- flow.prop(view, "view_frame_seconds")
+ col.prop(view, "view_frame_seconds")
elif view.view_frame_type == 'KEYFRAMES':
- flow.prop(view, "view_frame_keyframes")
+ col.prop(view, "view_frame_keyframes")
class USERPREF_PT_animation_keyframes(AnimationPanel, CenterAlignMixIn, Panel):
@@ -511,25 +501,14 @@ class USERPREF_PT_animation_keyframes(AnimationPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
edit = prefs.edit
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(edit, "use_visual_keying")
- flow.prop(edit, "use_keyframe_insert_needed", text="Only Insert Needed")
-
-
-class USERPREF_PT_animation_autokey(AnimationPanel, CenterAlignMixIn, Panel):
- bl_label = "Auto-Keyframing"
- bl_parent_id = "USERPREF_PT_animation_keyframes"
-
- def draw_centered(self, context, layout):
- prefs = context.preferences
- edit = prefs.edit
-
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ col = layout.column()
+ col.prop(edit, "use_visual_keying")
+ col.prop(edit, "use_keyframe_insert_needed", text="Only Insert Needed")
- flow.prop(edit, "use_auto_keying_warning", text="Show Warning")
- flow.prop(edit, "use_keyframe_insert_available", text="Only Insert Available")
- flow.prop(edit, "use_auto_keying", text="Enable in New Scenes")
+ col = layout.column(heading="Auto-Keyframing")
+ col.prop(edit, "use_auto_keying_warning", text="Show Warning")
+ col.prop(edit, "use_keyframe_insert_available", text="Only Insert Available")
+ col.prop(edit, "use_auto_keying", text="Enable in New Scenes")
class USERPREF_PT_animation_fcurves(AnimationPanel, CenterAlignMixIn, Panel):
@@ -605,23 +584,27 @@ class USERPREF_PT_system_memory(SystemPanel, CenterAlignMixIn, Panel):
system = prefs.system
edit = prefs.edit
- layout.prop(edit, "undo_steps", text="Undo Steps")
- layout.prop(edit, "undo_memory_limit", text="Undo Memory Limit")
- layout.prop(edit, "use_global_undo")
+ col = layout.column()
+ col.prop(edit, "undo_steps", text="Undo Steps")
+ col.prop(edit, "undo_memory_limit", text="Undo Memory Limit")
+ col.prop(edit, "use_global_undo")
layout.separator()
- layout.prop(system, "texture_time_out", text="Texture Time Out")
- layout.prop(system, "texture_collection_rate", text="Garbage Collection Rate")
+ col = layout.column()
+ col.prop(system, "scrollback", text="Console Scrollback Lines")
layout.separator()
- layout.prop(system, "vbo_time_out", text="Vbo Time Out")
- layout.prop(system, "vbo_collection_rate", text="Garbage Collection Rate")
+ col = layout.column()
+ col.prop(system, "texture_time_out", text="Texture Time Out")
+ col.prop(system, "texture_collection_rate", text="Garbage Collection Rate")
layout.separator()
- layout.prop(system, "scrollback", text="Console Scrollback Lines")
+ col = layout.column()
+ col.prop(system, "vbo_time_out", text="Vbo Time Out")
+ col.prop(system, "vbo_collection_rate", text="Garbage Collection Rate")
class USERPREF_PT_system_video_sequencer(SystemPanel, CenterAlignMixIn, Panel):
@@ -660,23 +643,19 @@ class USERPREF_PT_viewport_display(ViewportPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
view = prefs.view
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(view, "show_object_info", text="Object Info")
- flow.prop(view, "show_view_name", text="View Name")
- flow.prop(view, "show_playback_fps", text="Playback FPS")
+ col = layout.column(heading="Show")
+ col.prop(view, "show_object_info", text="Object Info")
+ col.prop(view, "show_view_name", text="View Name")
+ col.prop(view, "show_playback_fps", text="Playback FPS")
layout.separator()
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
+ col = layout.column()
col.prop(view, "gizmo_size")
col.prop(view, "lookdev_sphere_size")
- flow.separator()
+ col.separator()
- col = flow.column()
col.prop(view, "mini_axis_type", text="3D Viewport Axis")
if view.mini_axis_type == 'MINIMAL':
@@ -691,11 +670,12 @@ class USERPREF_PT_viewport_quality(ViewportPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
system = prefs.system
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ col = layout.column()
+ col.prop(system, "viewport_aa")
- flow.prop(system, "viewport_aa")
- flow.prop(system, "use_overlay_smooth_wire")
- flow.prop(system, "use_edit_mode_smooth_wire")
+ col = layout.column(heading="Smooth Wires")
+ col.prop(system, "use_overlay_smooth_wire", text="Overlay")
+ col.prop(system, "use_edit_mode_smooth_wire", text="Edit Mode")
class USERPREF_PT_viewport_textures(ViewportPanel, CenterAlignMixIn, Panel):
@@ -705,12 +685,11 @@ class USERPREF_PT_viewport_textures(ViewportPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
system = prefs.system
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(system, "gl_texture_limit", text="Limit Size")
- flow.prop(system, "anisotropic_filter")
- flow.prop(system, "gl_clip_alpha", slider=True)
- flow.prop(system, "image_draw_method", text="Image Display Method")
+ col = layout.column()
+ col.prop(system, "gl_texture_limit", text="Limit Size")
+ col.prop(system, "anisotropic_filter")
+ col.prop(system, "gl_clip_alpha", slider=True)
+ col.prop(system, "image_draw_method", text="Image Display Method")
class USERPREF_PT_viewport_selection(ViewportPanel, CenterAlignMixIn, Panel):
@@ -721,9 +700,7 @@ class USERPREF_PT_viewport_selection(ViewportPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
system = prefs.system
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(system, "use_select_pick_depth")
+ layout.prop(system, "use_select_pick_depth")
# -----------------------------------------------------------------------------
@@ -1331,37 +1308,40 @@ class USERPREF_PT_saveload_blend(SaveLoadPanel, CenterAlignMixIn, Panel):
paths = prefs.filepaths
view = prefs.view
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(paths, "use_relative_paths")
- flow.prop(paths, "use_file_compression")
- flow.prop(paths, "use_load_ui")
- flow.prop(paths, "use_save_preview_images")
- flow.prop(paths, "use_tabs_as_spaces")
- flow.prop(view, "use_save_prompt")
+ col = layout.column(heading="Save")
+ col.prop(view, "use_save_prompt")
+ col.prop(paths, "use_save_preview_images")
- layout.separator()
+ col = layout.column(heading="Default to")
+ col.prop(paths, "use_relative_paths")
+ col.prop(paths, "use_file_compression")
+ col.prop(paths, "use_load_ui")
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ col = layout.column(heading="Text Files")
+ col.prop(paths, "use_tabs_as_spaces")
- flow.prop(paths, "save_version")
- flow.prop(paths, "recent_files")
+ col = layout.column()
+ col.prop(paths, "save_version")
+ col.prop(paths, "recent_files")
class USERPREF_PT_saveload_blend_autosave(SaveLoadPanel, CenterAlignMixIn, Panel):
bl_label = "Auto Save"
bl_parent_id = "USERPREF_PT_saveload_blend"
- def draw_centered(self, context, layout):
+ def draw_header(self, context):
prefs = context.preferences
paths = prefs.filepaths
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ self.layout.prop(paths, "use_auto_save_temporary_files", text="")
- flow.prop(paths, "use_auto_save_temporary_files")
- sub = flow.column()
- sub.active = paths.use_auto_save_temporary_files
- sub.prop(paths, "auto_save_time", text="Timer (mins)")
+ def draw_centered(self, context, layout):
+ prefs = context.preferences
+ paths = prefs.filepaths
+
+ col = layout.column()
+ col.active = paths.use_auto_save_temporary_files
+ col.prop(paths, "auto_save_time", text="Timer (mins)")
class USERPREF_PT_saveload_file_browser(SaveLoadPanel, CenterAlignMixIn, Panel):
@@ -1371,12 +1351,13 @@ class USERPREF_PT_saveload_file_browser(SaveLoadPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
paths = prefs.filepaths
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ col = layout.column()
+ col.prop(paths, "use_filter_files")
- flow.prop(paths, "use_filter_files")
- flow.prop(paths, "show_hidden_files_datablocks")
- flow.prop(paths, "hide_recent_locations")
- flow.prop(paths, "hide_system_bookmarks")
+ col = layout.column(heading="Hide")
+ col.prop(paths, "show_hidden_files_datablocks", text="Dot File & Datablocks")
+ col.prop(paths, "hide_recent_locations", text="Recent Locations")
+ col.prop(paths, "hide_system_bookmarks", text="System Bookmarks")
# -----------------------------------------------------------------------------
@@ -1435,10 +1416,9 @@ class USERPREF_PT_input_tablet(InputPanel, CenterAlignMixIn, Panel):
layout.prop(inputs, "tablet_api")
layout.separator()
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(inputs, "pressure_threshold_max")
- flow.prop(inputs, "pressure_softness")
+ col = layout.column()
+ col.prop(inputs, "pressure_threshold_max")
+ col.prop(inputs, "pressure_softness")
class USERPREF_PT_input_ndof(InputPanel, CenterAlignMixIn, Panel):
@@ -1485,24 +1465,27 @@ class USERPREF_PT_navigation_orbit(NavigationPanel, CenterAlignMixIn, Panel):
inputs = prefs.inputs
view = prefs.view
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ col = layout.column()
- flow.row().prop(inputs, "view_rotate_method", expand=True)
+ col.row().prop(inputs, "view_rotate_method", expand=True)
if inputs.view_rotate_method == 'TURNTABLE':
- flow.prop(inputs, "view_rotate_sensitivity_turntable")
+ col.prop(inputs, "view_rotate_sensitivity_turntable")
else:
- flow.prop(inputs, "view_rotate_sensitivity_trackball")
+ col.prop(inputs, "view_rotate_sensitivity_trackball")
+ col.prop(inputs, "use_rotate_around_active")
+
+ col.separator()
- flow.prop(inputs, "use_rotate_around_active")
- flow.prop(inputs, "use_auto_perspective")
- flow.prop(inputs, "use_mouse_depth_navigate")
if sys.platform == "darwin":
- flow.prop(inputs, "use_trackpad_natural", text="Natural Trackpad Direction")
+ col.prop(inputs, "use_trackpad_natural", text="Natural Trackpad Direction")
- flow.separator()
+ col = layout.column(heading="Auto")
+ col.prop(inputs, "use_auto_perspective", text="Perspective")
+ col.prop(inputs, "use_mouse_depth_navigate", text="Depth")
- flow.prop(view, "smooth_view")
- flow.prop(view, "rotation_angle")
+ col = layout.column()
+ col.prop(view, "smooth_view")
+ col.prop(view, "rotation_angle")
class USERPREF_PT_navigation_zoom(NavigationPanel, CenterAlignMixIn, Panel):
@@ -1512,16 +1495,20 @@ class USERPREF_PT_navigation_zoom(NavigationPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
inputs = prefs.inputs
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ col = layout.column()
- flow.row().prop(inputs, "view_zoom_method", text="Zoom Method")
+ col.row().prop(inputs, "view_zoom_method", text="Zoom Method")
if inputs.view_zoom_method in {'DOLLY', 'CONTINUE'}:
- flow.row().prop(inputs, "view_zoom_axis")
- flow.prop(inputs, "invert_mouse_zoom", text="Invert Mouse Zoom Direction")
+ col.row().prop(inputs, "view_zoom_axis")
+ col.prop(inputs, "use_zoom_to_mouse")
+ col = layout.column(heading="Invert Zoom Direction", align=True)
+ col.prop(inputs, "invert_mouse_zoom", text="Mouse")
+ col.prop(inputs, "invert_zoom_wheel", text="Wheel")
+ else:
+ col.prop(inputs, "use_zoom_to_mouse")
+ col.prop(inputs, "invert_zoom_wheel", text="Invert Wheel Zoom Direction")
- flow.prop(inputs, "invert_zoom_wheel", text="Invert Wheel Zoom Direction")
# sub.prop(view, "wheel_scroll_lines", text="Scroll Lines")
- flow.prop(inputs, "use_zoom_to_mouse")
class USERPREF_PT_navigation_fly_walk(NavigationPanel, CenterAlignMixIn, Panel):
@@ -1552,15 +1539,14 @@ class USERPREF_PT_navigation_fly_walk_navigation(NavigationPanel, CenterAlignMix
inputs = prefs.inputs
walk = inputs.walk_navigation
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(walk, "use_mouse_reverse")
- flow.prop(walk, "mouse_speed")
- flow.prop(walk, "teleport_time")
+ col = layout.column()
+ col.prop(walk, "use_mouse_reverse")
+ col.prop(walk, "mouse_speed")
+ col.prop(walk, "teleport_time")
- sub = flow.column(align=True)
- sub.prop(walk, "walk_speed")
- sub.prop(walk, "walk_speed_factor")
+ col = layout.column(align=True)
+ col.prop(walk, "walk_speed")
+ col.prop(walk, "walk_speed_factor")
class USERPREF_PT_navigation_fly_walk_gravity(NavigationPanel, CenterAlignMixIn, Panel):
@@ -1587,10 +1573,9 @@ class USERPREF_PT_navigation_fly_walk_gravity(NavigationPanel, CenterAlignMixIn,
layout.active = walk.use_gravity
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(walk, "view_height")
- flow.prop(walk, "jump_height")
+ col = layout.column()
+ col.prop(walk, "view_height")
+ col.prop(walk, "jump_height")
# Special case, this is only exposed as a popover.
@@ -2135,7 +2120,7 @@ class ExperimentalPanel:
experimental = prefs.experimental
layout = self.layout
- layout.use_property_split = True
+ layout.use_property_split = False
layout.use_property_decorate = False
for prop_keywords, task in items:
@@ -2161,16 +2146,6 @@ class USERPREF_PT_experimental_virtual_reality(ExperimentalPanel, Panel):
)
"""
-class USERPREF_PT_experimental_ui(ExperimentalPanel, Panel):
- bl_label = "UI"
-
- def draw(self, context):
- self._draw_items(
- context, (
- ({"property": "use_menu_search"}, "T74157"),
- ),
- )
-
class USERPREF_PT_experimental_system(ExperimentalPanel, Panel):
bl_label = "System"
@@ -2223,7 +2198,6 @@ classes = (
USERPREF_PT_animation_timeline,
USERPREF_PT_animation_keyframes,
- USERPREF_PT_animation_autokey,
USERPREF_PT_animation_fcurves,
USERPREF_PT_system_cycles_devices,
@@ -2274,7 +2248,6 @@ classes = (
# Popovers.
USERPREF_PT_ndof_settings,
- USERPREF_PT_experimental_ui,
USERPREF_PT_experimental_system,
# Add dynamically generated editor theme panels last,
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 5d47566d880..3e4a3f5de4c 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -5301,6 +5301,7 @@ class VIEW3D_MT_sculpt_mask_edit_pie(Menu):
op.auto_iteration_count = False
class VIEW3D_MT_sculpt_face_sets_edit_pie(Menu):
+
bl_label = "Face Sets Edit"
def draw(self, _context):
@@ -5396,8 +5397,8 @@ class VIEW3D_PT_view3d_properties(Panel):
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True)
- col = flow.column()
+
+ col = layout.column()
subcol = col.column()
subcol.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews)
@@ -5407,20 +5408,22 @@ class VIEW3D_PT_view3d_properties(Panel):
subcol.prop(view, "clip_start", text="Clip Start")
subcol.prop(view, "clip_end", text="End")
- subcol.separator()
-
- col = flow.column()
+ layout.separator()
- subcol = col.column()
- subcol.prop(view, "use_local_camera")
+ col = layout.column(align=False, heading="Local Camera")
+ col.use_property_decorate = False
+ row = col.row(align=True)
+ sub = row.row(align=True)
+ sub.prop(view, "use_local_camera", text="")
+ sub = sub.row(align=True)
+ sub.enabled = view.use_local_camera
+ sub.prop(view, "camera", text="")
- subcol = col.column()
- subcol.enabled = view.use_local_camera
- subcol.prop(view, "camera", text="Local Camera")
+ layout.separator()
- subcol = col.column(align=True)
- subcol.prop(view, "use_render_border")
- subcol.active = view.region_3d.view_perspective != 'CAMERA'
+ col = layout.column(align=True)
+ col.prop(view, "use_render_border")
+ col.active = view.region_3d.view_perspective != 'CAMERA'
class VIEW3D_PT_view3d_lock(Panel):
@@ -5439,23 +5442,24 @@ class VIEW3D_PT_view3d_lock(Panel):
view = context.space_data
col = layout.column(align=True)
- subcol = col.column()
- subcol.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews)
+ sub = col.column()
+ sub.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews)
- subcol.prop(view, "lock_object")
+ sub.prop(view, "lock_object")
lock_object = view.lock_object
if lock_object:
if lock_object.type == 'ARMATURE':
- subcol.prop_search(
+ sub.prop_search(
view, "lock_bone", lock_object.data,
"edit_bones" if lock_object.mode == 'EDIT'
else "bones",
text="",
)
else:
- subcol.prop(view, "lock_cursor", text="Lock to 3D Cursor")
+ subcol = sub.column(heading="Lock")
+ subcol.prop(view, "lock_cursor", text="To 3D Cursor")
- col.prop(view, "lock_camera")
+ col.prop(view, "lock_camera", text="Camera to View")
class VIEW3D_PT_view3d_cursor(Panel):
@@ -6045,16 +6049,17 @@ class VIEW3D_PT_overlay_guides(Panel):
split = col.split()
sub = split.column()
sub.prop(overlay, "show_text", text="Text Info")
+ sub.prop(overlay, "show_stats", text="Statistics")
+
sub = split.column()
sub.prop(overlay, "show_cursor", text="3D Cursor")
+ sub.prop(overlay, "show_annotation", text="Annotations")
if shading.type == 'MATERIAL':
row = col.row()
row.active = shading.render_pass == 'COMBINED'
row.prop(overlay, "show_look_dev")
- col.prop(overlay, "show_annotation", text="Annotations")
-
class VIEW3D_PT_overlay_object(Panel):
bl_space_type = 'VIEW_3D'
@@ -7055,6 +7060,18 @@ def draw_gpencil_layer_active(context, layout):
row.operator("gpencil.layer_remove", text="", icon='X')
+def draw_gpencil_material_active(context, layout):
+ ob = context.active_object
+ if ob and len(ob.material_slots) > 0 and ob.active_material_index >= 0:
+ ma = ob.material_slots[ob.active_material_index].material
+ if ma:
+ layout.label(text="Active Material")
+ row = layout.row(align=True)
+ row.operator_context = 'EXEC_REGION_WIN'
+ row.operator_menu_enum("gpencil.material_set", "slot", text="", icon='MATERIAL')
+ row.prop(ma, "name", text="")
+
+
class VIEW3D_PT_gpencil_sculpt_context_menu(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
@@ -7128,6 +7145,9 @@ class VIEW3D_PT_gpencil_draw_context_menu(Panel):
# Layers
draw_gpencil_layer_active(context, layout)
+ # Material
+ if not is_vertex:
+ draw_gpencil_material_active(context, layout)
class VIEW3D_PT_gpencil_vertex_context_menu(Panel):
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 6aaeec3f3cf..04a3e6f62ea 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -125,21 +125,15 @@ class View3DPanel:
# Used by vertex & weight paint
def draw_vpaint_symmetry(layout, vpaint):
- split = layout.split()
-
- col = split.column()
- col.alignment = 'RIGHT'
- col.label(text="Mirror")
+ col = layout.column()
+ col.use_property_split = True
+ col.use_property_decorate = False
- col = split.column()
- row = col.row(align=True)
+ row = col.row(heading="Mirror", align=True)
row.prop(vpaint, "use_symmetry_x", text="X", toggle=True)
row.prop(vpaint, "use_symmetry_y", text="Y", toggle=True)
row.prop(vpaint, "use_symmetry_z", text="Z", toggle=True)
- col = layout.column()
- col.use_property_split = True
- col.use_property_decorate = False
col.prop(vpaint, "radial_symmetry", text="Radial")
@@ -179,10 +173,10 @@ class VIEW3D_PT_tools_object_options_transform(View3DPanel, Panel):
tool_settings = context.tool_settings
- layout.label(text="Affect Only")
- layout.prop(tool_settings, "use_transform_data_origin", text="Origins")
- layout.prop(tool_settings, "use_transform_pivot_point_align", text="Locations")
- layout.prop(tool_settings, "use_transform_skip_children", text="Parents")
+ col = layout.column(heading="Affect Only", align=True)
+ col.prop(tool_settings, "use_transform_data_origin", text="Origins")
+ col.prop(tool_settings, "use_transform_pivot_point_align", text="Locations")
+ col.prop(tool_settings, "use_transform_skip_children", text="Parents")
# ********** default tools for editmode_mesh ****************
@@ -209,16 +203,11 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
split = layout.split()
- col = split.column()
- col.alignment = 'RIGHT'
- col.label(text="Mirror")
-
- col = split.column()
-
- row = col.row(align=True)
- row.prop(mesh, "use_mirror_x", text="X", toggle=True)
- row.prop(mesh, "use_mirror_y", text="Y", toggle=True)
- row.prop(mesh, "use_mirror_z", text="Z", toggle=True)
+ row = layout.row(heading="Mirror")
+ sub = row.row(align=True)
+ sub.prop(mesh, "use_mirror_x", text="X", toggle=True)
+ sub.prop(mesh, "use_mirror_y", text="Y", toggle=True)
+ sub.prop(mesh, "use_mirror_z", text="Z", toggle=True)
row = layout.row(align=True)
row.active = ob.data.use_mirror_x or ob.data.use_mirror_y or ob.data.use_mirror_z
@@ -872,10 +861,13 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
col.prop(mesh, "remesh_voxel_adaptivity")
col.prop(mesh, "use_remesh_fix_poles")
col.prop(mesh, "use_remesh_smooth_normals")
- col.prop(mesh, "use_remesh_preserve_volume")
- col.prop(mesh, "use_remesh_preserve_paint_mask")
- col.prop(mesh, "use_remesh_preserve_sculpt_face_sets")
- col.operator("object.voxel_remesh", text="Remesh")
+
+ col = layout.column(heading="Preserve", align=True)
+ col.prop(mesh, "use_remesh_preserve_volume", text="Volume")
+ col.prop(mesh, "use_remesh_preserve_paint_mask", text="Paint Mask")
+ col.prop(mesh, "use_remesh_preserve_sculpt_face_sets", text="Face Sets")
+
+ layout.operator("object.voxel_remesh", text="Remesh")
# TODO, move to space_view3d.py
@@ -896,23 +888,19 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
tool_settings = context.tool_settings
sculpt = tool_settings.sculpt
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
+ col = layout.column(heading="Display", align=True)
col.prop(sculpt, "use_threaded", text="Threaded Sculpt")
- col = flow.column()
col.prop(sculpt, "show_low_resolution")
- col = flow.column()
col.prop(sculpt, "use_sculpt_delay_updates")
- col = flow.column()
col.prop(sculpt, "use_deform_only")
- col = flow.column()
col.separator()
- col.prop(sculpt, "use_automasking_topology")
- col.prop(sculpt, "use_automasking_face_sets")
- col.prop(sculpt, "use_automasking_boundary_edges")
- col.prop(sculpt, "use_automasking_boundary_face_sets")
+
+ col = layout.column(heading="Auto-Masking", align=True)
+ col.prop(sculpt, "use_automasking_topology", text="Topology")
+ col.prop(sculpt, "use_automasking_face_sets", text="Face Sets")
+ col.prop(sculpt, "use_automasking_boundary_edges", text="Boundary Edges")
+ col.prop(sculpt, "use_automasking_boundary_face_sets", text="Boundary Face Sets")
class VIEW3D_PT_sculpt_options_gravity(Panel, View3DPaintPanel):
@@ -955,61 +943,34 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
sculpt = context.tool_settings.sculpt
- split = layout.split()
-
- col = split.column()
- col.alignment = 'RIGHT'
- col.label(text="Mirror")
-
- col = split.column()
-
- row = col.row(align=True)
+ row = layout.row(align=True, heading="Mirror")
row.prop(sculpt, "use_symmetry_x", text="X", toggle=True)
row.prop(sculpt, "use_symmetry_y", text="Y", toggle=True)
row.prop(sculpt, "use_symmetry_z", text="Z", toggle=True)
- split = layout.split()
-
- col = split.column()
- col.alignment = 'RIGHT'
- col.label(text="Lock")
-
- col = split.column()
-
- row = col.row(align=True)
+ row = layout.row(align=True, heading="Lock")
row.prop(sculpt, "lock_x", text="X", toggle=True)
row.prop(sculpt, "lock_y", text="Y", toggle=True)
row.prop(sculpt, "lock_z", text="Z", toggle=True)
- split = layout.split()
-
- col = split.column()
- col.alignment = 'RIGHT'
- col.label(text="Tiling")
-
- col = split.column()
-
- row = col.row(align=True)
+ row = layout.row(align=True, heading="Tiling")
row.prop(sculpt, "tile_x", text="X", toggle=True)
row.prop(sculpt, "tile_y", text="Y", toggle=True)
row.prop(sculpt, "tile_z", text="Z", toggle=True)
- layout.use_property_split = True
- layout.use_property_decorate = False
-
layout.prop(sculpt, "use_symmetry_feather", text="Feather")
- layout.column().prop(sculpt, "radial_symmetry", text="Radial")
- layout.column().prop(sculpt, "tile_offset", text="Tile Offset")
+ layout.prop(sculpt, "radial_symmetry", text="Radial")
+ layout.prop(sculpt, "tile_offset", text="Tile Offset")
layout.separator()
- col = layout.column()
-
- col.prop(sculpt, "symmetrize_direction")
- col.operator("sculpt.symmetrize")
+ layout.prop(sculpt, "symmetrize_direction")
+ layout.operator("sculpt.symmetrize")
class VIEW3D_PT_sculpt_symmetry_for_topbar(Panel):
@@ -1212,12 +1173,8 @@ class VIEW3D_PT_tools_imagepaint_options(View3DPaintPanel, Panel):
layout.prop(ipaint, "seam_bleed")
layout.prop(ipaint, "dither", slider=True)
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
+ col = layout.column()
col.prop(ipaint, "use_occlude")
-
- col = flow.column()
col.prop(ipaint, "use_backface_culling", text="Backface Culling")
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 969a1ca1bd7..2dc6c6cd409 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -58,6 +58,13 @@ class TextureNodeCategory(SortedNodeCategory):
context.space_data.tree_type == 'TextureNodeTree')
+class SimulationNodeCategory(SortedNodeCategory):
+ @classmethod
+ def poll(cls, context):
+ return (context.space_data.type == 'NODE_EDITOR' and
+ context.space_data.tree_type == 'SimulationNodeTree')
+
+
# menu entry for node group tools
def group_tools_draw(self, layout, context):
layout.operator("node.group_make")
@@ -70,10 +77,11 @@ node_tree_group_type = {
'CompositorNodeTree': 'CompositorNodeGroup',
'ShaderNodeTree': 'ShaderNodeGroup',
'TextureNodeTree': 'TextureNodeGroup',
+ 'SimulationNodeTree': 'SimulationNodeGroup',
}
-# generic node group items generator for shader, compositor and texture node groups
+# generic node group items generator for shader, compositor, simulation and texture node groups
def node_group_items(context):
if context is None:
return
@@ -467,17 +475,81 @@ texture_node_categories = [
]),
]
+simulation_node_categories = [
+ # Simulation Nodes
+ SimulationNodeCategory("SIM_OUTPUT", "Output", items=[
+ NodeItem("SimulationNodeParticleSimulation"),
+ ]),
+ SimulationNodeCategory("SIM_INPUTS", "Input", items=[
+ NodeItem("SimulationNodeTime"),
+ NodeItem("SimulationNodeParticleAttribute"),
+ NodeItem("FunctionNodeGroupInstanceID"),
+ ]),
+ SimulationNodeCategory("SIM_EMITTERS", "Emitters", items=[
+ NodeItem("SimulationNodeParticleMeshEmitter"),
+ NodeItem("SimulationNodeEmitParticles"),
+ ]),
+ SimulationNodeCategory("SIM_EVENTS", "Events", items=[
+ NodeItem("SimulationNodeParticleBirthEvent"),
+ NodeItem("SimulationNodeParticleTimeStepEvent"),
+ NodeItem("SimulationNodeParticleMeshCollisionEvent"),
+ ]),
+ SimulationNodeCategory("SIM_FORCES", "Forces", items=[
+ NodeItem("SimulationNodeForce"),
+ ]),
+ SimulationNodeCategory("SIM_EXECUTE", "Execute", items=[
+ NodeItem("SimulationNodeSetParticleAttribute"),
+ NodeItem("SimulationNodeExecuteCondition"),
+ NodeItem("SimulationNodeMultiExecute"),
+ ]),
+ SimulationNodeCategory("SIM_NOISE", "Noise", items=[
+ NodeItem("ShaderNodeTexNoise"),
+ NodeItem("ShaderNodeTexWhiteNoise"),
+ ]),
+ SimulationNodeCategory("SIM_COLOR", "Color", items=[
+ NodeItem("ShaderNodeMixRGB"),
+ NodeItem("ShaderNodeInvert"),
+ NodeItem("ShaderNodeHueSaturation"),
+ NodeItem("ShaderNodeGamma"),
+ NodeItem("ShaderNodeBrightContrast"),
+ ]),
+ SimulationNodeCategory("SIM_CONVERTER", "Converter", items=[
+ NodeItem("ShaderNodeMapRange"),
+ NodeItem("ShaderNodeClamp"),
+ NodeItem("ShaderNodeMath"),
+ NodeItem("ShaderNodeValToRGB"),
+ NodeItem("ShaderNodeVectorMath"),
+ NodeItem("ShaderNodeSeparateRGB"),
+ NodeItem("ShaderNodeCombineRGB"),
+ NodeItem("ShaderNodeSeparateXYZ"),
+ NodeItem("ShaderNodeCombineXYZ"),
+ NodeItem("ShaderNodeSeparateHSV"),
+ NodeItem("ShaderNodeCombineHSV"),
+ NodeItem("FunctionNodeBooleanMath"),
+ NodeItem("FunctionNodeFloatCompare"),
+ NodeItem("FunctionNodeSwitch"),
+ NodeItem("FunctionNodeCombineStrings"),
+ ]),
+ SimulationNodeCategory("SIM_GROUP", "Group", items=node_group_items),
+ SimulationNodeCategory("SIM_LAYOUT", "Layout", items=[
+ NodeItem("NodeFrame"),
+ NodeItem("NodeReroute"),
+ ]),
+]
+
def register():
nodeitems_utils.register_node_categories('SHADER', shader_node_categories)
nodeitems_utils.register_node_categories('COMPOSITING', compositor_node_categories)
nodeitems_utils.register_node_categories('TEXTURE', texture_node_categories)
+ nodeitems_utils.register_node_categories('SIMULATION', simulation_node_categories)
def unregister():
nodeitems_utils.unregister_node_categories('SHADER')
nodeitems_utils.unregister_node_categories('COMPOSITING')
nodeitems_utils.unregister_node_categories('TEXTURE')
+ nodeitems_utils.unregister_node_categories('SIMULATION')
if __name__ == "__main__":
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index f6f1393bd21..ddb88cf61ed 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -117,9 +117,11 @@ void BLF_draw_ascii(int fontid, const char *str, size_t len) ATTR_NONNULL(2);
int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) ATTR_NONNULL(2);
typedef bool (*BLF_GlyphBoundsFn)(const char *str,
- const size_t str_ofs,
- const struct rcti *glyph_bounds,
+ const size_t str_step_ofs,
+ const struct rcti *glyph_step_bounds,
const int glyph_advance_x,
+ const struct rctf *glyph_bounds,
+ const int glyph_bearing[2],
void *user_data);
void BLF_boundbox_foreach_glyph_ex(int fontid,
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 394704e1c20..2f7d5a60a6f 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -946,8 +946,8 @@ void BLF_buffer(int fontid,
if (font) {
font->buf_info.fbuf = fbuf;
font->buf_info.cbuf = cbuf;
- font->buf_info.w = w;
- font->buf_info.h = h;
+ font->buf_info.dims[0] = w;
+ font->buf_info.dims[1] = h;
font->buf_info.ch = nch;
font->buf_info.display = display;
}
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index ed92e9aaff2..e5e03418073 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -613,28 +613,28 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
}
- chx = pen_x + ((int)g->pos_x);
- chy = pen_y_basis + g->height;
+ chx = pen_x + ((int)g->pos[0]);
+ chy = pen_y_basis + g->dims[1];
if (g->pitch < 0) {
- pen_y = pen_y_basis + (g->height - (int)g->pos_y);
+ pen_y = pen_y_basis + (g->dims[1] - g->pos[1]);
}
else {
- pen_y = pen_y_basis - (g->height - (int)g->pos_y);
+ pen_y = pen_y_basis - (g->dims[1] - g->pos[1]);
}
- if ((chx + g->width) >= 0 && chx < buf_info->w && (pen_y + g->height) >= 0 &&
- pen_y < buf_info->h) {
+ if ((chx + g->dims[0]) >= 0 && chx < buf_info->dims[0] && (pen_y + g->dims[1]) >= 0 &&
+ pen_y < buf_info->dims[1]) {
/* don't draw beyond the buffer bounds */
- int width_clip = g->width;
- int height_clip = g->height;
- int yb_start = g->pitch < 0 ? 0 : g->height - 1;
+ int width_clip = g->dims[0];
+ int height_clip = g->dims[1];
+ int yb_start = g->pitch < 0 ? 0 : g->dims[1] - 1;
- if (width_clip + chx > buf_info->w) {
- width_clip -= chx + width_clip - buf_info->w;
+ if (width_clip + chx > buf_info->dims[0]) {
+ width_clip -= chx + width_clip - buf_info->dims[0];
}
- if (height_clip + pen_y > buf_info->h) {
- height_clip -= pen_y + height_clip - buf_info->h;
+ if (height_clip + pen_y > buf_info->dims[1]) {
+ height_clip -= pen_y + height_clip - buf_info->dims[1];
}
/* drawing below the image? */
@@ -652,7 +652,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
if (a_byte) {
const float a = (a_byte / 255.0f) * b_col_float[3];
const size_t buf_ofs = (((size_t)(chx + x) +
- ((size_t)(pen_y + y) * (size_t)buf_info->w)) *
+ ((size_t)(pen_y + y) * (size_t)buf_info->dims[0])) *
(size_t)buf_info->ch);
float *fbuf = buf_info->fbuf + buf_ofs;
@@ -689,7 +689,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
if (a_byte) {
const float a = (a_byte / 255.0f) * b_col_float[3];
const size_t buf_ofs = (((size_t)(chx + x) +
- ((size_t)(pen_y + y) * (size_t)buf_info->w)) *
+ ((size_t)(pen_y + y) * (size_t)buf_info->dims[0])) *
(size_t)buf_info->ch);
unsigned char *cbuf = buf_info->cbuf + buf_ofs;
@@ -1246,13 +1246,13 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
}
gbox.xmin = pen_x;
- gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->width);
+ gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]);
gbox.ymin = pen_y;
- gbox.ymax = gbox.ymin - g->height;
+ gbox.ymax = gbox.ymin - g->dims[1];
pen_x += g->advance_i;
- if (user_fn(str, i_curr, &gbox, g->advance_i, user_data) == false) {
+ if (user_fn(str, i_curr, &gbox, g->advance_i, &g->box, g->pos, user_data) == false) {
break;
}
@@ -1365,8 +1365,8 @@ static void blf_font_fill(FontBLF *font)
font->buf_info.fbuf = NULL;
font->buf_info.cbuf = NULL;
- font->buf_info.w = 0;
- font->buf_info.h = 0;
+ font->buf_info.dims[0] = 0;
+ font->buf_info.dims[1] = 0;
font->buf_info.ch = 0;
font->buf_info.col_init[0] = 0;
font->buf_info.col_init[1] = 0;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index a38cb323777..ce17069e53f 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -212,7 +212,7 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc)
GlyphBLF *g;
unsigned int i;
- for (i = 0; i < 257; i++) {
+ for (i = 0; i < ARRAY_SIZE(gc->bucket); i++) {
while ((g = BLI_pophead(&gc->bucket[i]))) {
blf_glyph_free(g);
}
@@ -327,26 +327,27 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un
g->c = c;
g->idx = (FT_UInt)index;
bitmap = slot->bitmap;
- g->width = (int)bitmap.width;
- g->height = (int)bitmap.rows;
+ g->dims[0] = (int)bitmap.width;
+ g->dims[1] = (int)bitmap.rows;
- if (g->width && g->height) {
+ const int buffer_size = g->dims[0] * g->dims[1];
+
+ if (buffer_size != 0) {
if (font->flags & BLF_MONOCHROME) {
/* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */
- int i;
- for (i = 0; i < (g->width * g->height); i++) {
+ for (int i = 0; i < buffer_size; i++) {
bitmap.buffer[i] = bitmap.buffer[i] ? 255 : 0;
}
}
- g->bitmap = (unsigned char *)MEM_mallocN((size_t)g->width * (size_t)g->height, "glyph bitmap");
- memcpy((void *)g->bitmap, (void *)bitmap.buffer, (size_t)g->width * (size_t)g->height);
+ g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap");
+ memcpy(g->bitmap, bitmap.buffer, (size_t)buffer_size);
}
g->advance = ((float)slot->advance.x) / 64.0f;
g->advance_i = (int)g->advance;
- g->pos_x = (float)slot->bitmap_left;
- g->pos_y = (float)slot->bitmap_top;
+ g->pos[0] = slot->bitmap_left;
+ g->pos[1] = slot->bitmap_top;
g->pitch = slot->bitmap.pitch;
FT_Outline_Get_CBox(&(slot->outline), &bbox);
@@ -431,10 +432,10 @@ static void blf_texture3_draw(const unsigned char color_in[4],
static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y)
{
- rect->xmin = floorf(x + g->pos_x);
- rect->xmax = rect->xmin + (float)g->width;
- rect->ymin = floorf(y + g->pos_y);
- rect->ymax = rect->ymin - (float)g->height;
+ rect->xmin = floorf(x + (float)g->pos[0]);
+ rect->xmax = rect->xmin + (float)g->dims[0];
+ rect->ymin = floorf(y + (float)g->pos[1]);
+ rect->ymax = rect->ymin - (float)g->dims[1];
}
static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y)
@@ -443,9 +444,9 @@ static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y)
* width used by BLF_width. This allows that the text slightly
* overlaps the clipping border to achieve better alignment. */
rect->xmin = floorf(x);
- rect->xmax = rect->xmin + MIN2(g->advance, (float)g->width);
+ rect->xmax = rect->xmin + MIN2(g->advance, (float)g->dims[0]);
rect->ymin = floorf(y);
- rect->ymax = rect->ymin - (float)g->height;
+ rect->ymax = rect->ymin - (float)g->dims[1];
}
static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y, FontBLF *font)
@@ -455,7 +456,7 @@ static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y
void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y)
{
- if ((!g->width) || (!g->height)) {
+ if ((!g->dims[0]) || (!g->dims[1])) {
return;
}
@@ -466,7 +467,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
g->offset = gc->bitmap_len;
- int buff_size = g->width * g->height;
+ int buff_size = g->dims[0] * g->dims[1];
int bitmap_len = gc->bitmap_len + buff_size;
if (bitmap_len > gc->bitmap_len_alloc) {
@@ -514,7 +515,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
if (font->shadow == 0) {
blf_texture_draw(font->shadow_color,
- (int[2]){g->width, g->height},
+ g->dims,
g->offset,
rect_ofs.xmin,
rect_ofs.ymin,
@@ -523,7 +524,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
}
else if (font->shadow <= 4) {
blf_texture3_draw(font->shadow_color,
- (int[2]){g->width, g->height},
+ g->dims,
g->offset,
rect_ofs.xmin,
rect_ofs.ymin,
@@ -532,7 +533,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
}
else {
blf_texture5_draw(font->shadow_color,
- (int[2]){g->width, g->height},
+ g->dims,
g->offset,
rect_ofs.xmin,
rect_ofs.ymin,
@@ -547,39 +548,18 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
#if BLF_BLUR_ENABLE
switch (font->blur) {
case 3:
- blf_texture3_draw(font->color,
- (int[2]){g->width, g->height},
- g->offset,
- rect.xmin,
- rect.ymin,
- rect.xmax,
- rect.ymax);
+ blf_texture3_draw(
+ font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
break;
case 5:
- blf_texture5_draw(font->color,
- (int[2]){g->width, g->height},
- g->offset,
- rect.xmin,
- rect.ymin,
- rect.xmax,
- rect.ymax);
+ blf_texture5_draw(
+ font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
break;
default:
- blf_texture_draw(font->color,
- (int[2]){g->width, g->height},
- g->offset,
- rect.xmin,
- rect.ymin,
- rect.xmax,
- rect.ymax);
+ blf_texture_draw(
+ font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
}
#else
- blf_texture_draw(font->color,
- (int[2]){g->width, g->height},
- g->offset,
- rect.xmin,
- rect.ymin,
- rect.xmax,
- rect.ymax);
+ blf_texture_draw(font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
#endif
}
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 98ada87d16d..4ae592d323f 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -103,9 +103,11 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font,
const char *str,
size_t len,
bool (*user_fn)(const char *str,
- const size_t str_ofs,
- const struct rcti *glyph_bounds,
+ const size_t str_step_ofs,
+ const struct rcti *glyph_step_bounds,
const int glyph_advance_x,
+ const struct rctf *glyph_bounds,
+ const int glyph_bearing[2],
void *user_data),
void *user_data,
struct ResultBLF *r_info);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 6fae3eb4376..362cbf6730f 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -119,17 +119,16 @@ typedef struct GlyphBLF {
*/
unsigned char *bitmap;
- /* glyph width and height. */
- int width;
- int height;
+ /* Glyph width and height. */
+ int dims[2];
int pitch;
- /* X and Y bearing of the glyph.
+ /**
+ * X and Y bearing of the glyph.
* The X bearing is from the origin to the glyph left bbox edge.
* The Y bearing is from the baseline to the top of the glyph edge.
*/
- float pos_x;
- float pos_y;
+ int pos[2];
struct GlyphCacheBLF *glyph_cache;
} GlyphBLF;
@@ -141,9 +140,8 @@ typedef struct FontBufInfoBLF {
/* the same but unsigned char */
unsigned char *cbuf;
- /* buffer size, keep signed so comparisons with negative values work */
- int w;
- int h;
+ /** Buffer size, keep signed so comparisons with negative values work. */
+ int dims[2];
/* number of channels. */
int ch;
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index b7308d47d71..37eed29f6fe 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -78,8 +78,8 @@ void BLF_thumb_preview(const char *filename,
/* Would be done via the BLF API, but we're not using a fontid here */
font->buf_info.cbuf = buf;
font->buf_info.ch = channels;
- font->buf_info.w = w;
- font->buf_info.h = h;
+ font->buf_info.dims[0] = w;
+ font->buf_info.dims[1] = h;
/* Always create the image with a white font,
* the caller can theme how it likes */
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index a8915c178d4..4076bca3b19 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -207,17 +207,15 @@ bool BKE_animsys_read_rna_setting(struct PathResolvedRNA *anim_rna, float *r_val
bool BKE_animsys_write_rna_setting(struct PathResolvedRNA *anim_rna, const float value);
/* Evaluation loop for evaluating animation data */
-void BKE_animsys_evaluate_animdata(struct Scene *scene,
- struct ID *id,
+void BKE_animsys_evaluate_animdata(struct ID *id,
struct AnimData *adt,
float ctime,
- short recalc,
+ eAnimData_Recalc recalc,
const bool flush_to_original);
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */
void BKE_animsys_evaluate_all_animation(struct Main *main,
struct Depsgraph *depsgraph,
- struct Scene *scene,
float ctime);
/* ------------ Specialized API --------------- */
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 6c383ae5011..e59d5728350 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -27,6 +27,8 @@
extern "C" {
#endif
+#include "BLI_listbase.h"
+
struct Bone;
struct Depsgraph;
struct ListBase;
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index c9b70d681f4..bc64f78ffae 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -26,8 +26,8 @@
*
* \note Use #STRINGIFY() rather than defining with quotes.
*/
-#define BLENDER_VERSION 283
-#define BLENDER_SUBVERSION 15
+#define BLENDER_VERSION 290
+#define BLENDER_SUBVERSION 0
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
@@ -36,7 +36,7 @@
/** Can be left blank, otherwise a,b,c... etc with no quotes. */
#define BLENDER_VERSION_CHAR
/** alpha/beta/rc/release, docs use this. */
-#define BLENDER_VERSION_CYCLE beta
+#define BLENDER_VERSION_CYCLE alpha
/** Optionally set to 1,2,... for example to get alpha1 or rc2. */
#define BLENDER_VERSION_CYCLE_NUMBER
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 164867b228b..3524be99d0a 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -111,6 +111,8 @@ void BKE_curve_material_index_clear(struct Curve *cu);
bool BKE_curve_material_index_validate(struct Curve *cu);
void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len);
+void BKE_curve_smooth_flag_set(struct Curve *cu, const bool use_smooth);
+
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
int BKE_curve_nurb_vert_index_get(const struct Nurb *nu, const void *vert);
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index d389b557503..e620beb6ccc 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -29,8 +29,6 @@ extern "C" {
#endif
struct ChannelDriver;
-struct DriverTarget;
-struct DriverVar;
struct FCM_EnvelopeData;
struct FCurve;
struct FModifier;
@@ -56,67 +54,6 @@ typedef struct CfraElem {
void bezt_add_to_cfra_elem(ListBase *lb, struct BezTriple *bezt);
-/* ************** F-Curve Drivers ***************** */
-
-/* With these iterators for convenience, the variables "tarIndex" and "dtar" can be
- * accessed directly from the code using them, but it is not recommended that their
- * values be changed to point at other slots...
- */
-
-/* convenience looper over ALL driver targets for a given variable (even the unused ones) */
-#define DRIVER_TARGETS_LOOPER_BEGIN(dvar) \
- { \
- DriverTarget *dtar = &dvar->targets[0]; \
- int tarIndex = 0; \
- for (; tarIndex < MAX_DRIVER_TARGETS; tarIndex++, dtar++)
-
-/* convenience looper over USED driver targets only */
-#define DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) \
- { \
- DriverTarget *dtar = &dvar->targets[0]; \
- int tarIndex = 0; \
- for (; tarIndex < dvar->num_targets; tarIndex++, dtar++)
-
-/* tidy up for driver targets loopers */
-#define DRIVER_TARGETS_LOOPER_END \
- } \
- ((void)0)
-
-/* ---------------------- */
-
-void fcurve_free_driver(struct FCurve *fcu);
-struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
-
-void driver_variables_copy(struct ListBase *dst_vars, const struct ListBase *src_vars);
-
-void BKE_driver_target_matrix_to_rot_channels(
- float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]);
-
-void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
-void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
-
-void driver_change_variable_type(struct DriverVar *dvar, int type);
-void driver_variable_name_validate(struct DriverVar *dvar);
-struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
-
-float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar);
-bool driver_get_variable_property(struct ChannelDriver *driver,
- struct DriverTarget *dtar,
- struct PointerRNA *r_ptr,
- struct PropertyRNA **r_prop,
- int *r_index);
-
-bool BKE_driver_has_simple_expression(struct ChannelDriver *driver);
-bool BKE_driver_expression_depends_on_time(struct ChannelDriver *driver);
-void BKE_driver_invalidate_expression(struct ChannelDriver *driver,
- bool expr_changed,
- bool varname_changed);
-
-float evaluate_driver(struct PathResolvedRNA *anim_rna,
- struct ChannelDriver *driver,
- struct ChannelDriver *driver_orig,
- const float evaltime);
-
/* ************** F-Curve Modifiers *************** */
/* F-Curve Modifier Type-Info (fmi):
diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h
new file mode 100644
index 00000000000..ee531abfb72
--- /dev/null
+++ b/source/blender/blenkernel/BKE_fcurve_driver.h
@@ -0,0 +1,106 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ */
+
+#ifndef __BKE_FCURVE_DRIVER_H__
+#define __BKE_FCURVE_DRIVER_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ChannelDriver;
+struct DriverTarget;
+struct DriverVar;
+struct FCurve;
+struct PathResolvedRNA;
+struct PointerRNA;
+struct PropertyRNA;
+
+#include "DNA_curve_types.h"
+
+/* ************** F-Curve Drivers ***************** */
+
+/* With these iterators for convenience, the variables "tarIndex" and "dtar" can be
+ * accessed directly from the code using them, but it is not recommended that their
+ * values be changed to point at other slots...
+ */
+
+/* convenience looper over ALL driver targets for a given variable (even the unused ones) */
+#define DRIVER_TARGETS_LOOPER_BEGIN(dvar) \
+ { \
+ DriverTarget *dtar = &dvar->targets[0]; \
+ int tarIndex = 0; \
+ for (; tarIndex < MAX_DRIVER_TARGETS; tarIndex++, dtar++)
+
+/* convenience looper over USED driver targets only */
+#define DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) \
+ { \
+ DriverTarget *dtar = &dvar->targets[0]; \
+ int tarIndex = 0; \
+ for (; tarIndex < dvar->num_targets; tarIndex++, dtar++)
+
+/* tidy up for driver targets loopers */
+#define DRIVER_TARGETS_LOOPER_END \
+ } \
+ ((void)0)
+
+/* ---------------------- */
+
+void fcurve_free_driver(struct FCurve *fcu);
+struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
+
+void driver_variables_copy(struct ListBase *dst_vars, const struct ListBase *src_vars);
+
+void BKE_driver_target_matrix_to_rot_channels(
+ float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]);
+
+void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
+void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
+
+void driver_change_variable_type(struct DriverVar *dvar, int type);
+void driver_variable_name_validate(struct DriverVar *dvar);
+struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
+
+float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar);
+bool driver_get_variable_property(struct ChannelDriver *driver,
+ struct DriverTarget *dtar,
+ struct PointerRNA *r_ptr,
+ struct PropertyRNA **r_prop,
+ int *r_index);
+
+bool BKE_driver_has_simple_expression(struct ChannelDriver *driver);
+bool BKE_driver_expression_depends_on_time(struct ChannelDriver *driver);
+void BKE_driver_invalidate_expression(struct ChannelDriver *driver,
+ bool expr_changed,
+ bool varname_changed);
+
+float evaluate_driver(struct PathResolvedRNA *anim_rna,
+ struct ChannelDriver *driver,
+ struct ChannelDriver *driver_orig,
+ const float evaltime);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_FCURVE_DRIVER_H__*/
diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index 05545216217..6dc504c2007 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -165,6 +165,7 @@ extern IDTypeInfo IDType_ID_LP;
extern IDTypeInfo IDType_ID_HA;
extern IDTypeInfo IDType_ID_PT;
extern IDTypeInfo IDType_ID_VO;
+extern IDTypeInfo IDType_ID_SIM;
extern IDTypeInfo IDType_ID_LINK_PLACEHOLDER;
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 0d8b6efb4b1..37082947687 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -318,7 +318,7 @@ bool BKE_image_fill_tile(struct Image *ima,
bool is_float);
struct ImageTile *BKE_image_get_tile(struct Image *ima, int tile_number);
-struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, struct ImageUser *iuser);
+struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, const struct ImageUser *iuser);
int BKE_image_get_tile_from_pos(struct Image *ima,
const float uv[2],
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index ed1f67350c3..b2472e862ec 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -147,6 +147,7 @@ typedef struct Main {
ListBase hairs;
ListBase pointclouds;
ListBase volumes;
+ ListBase simulations;
/**
* Must be generated, used and freed by same code - never assume this is valid data unless you
@@ -220,7 +221,7 @@ const char *BKE_main_blendfile_path_from_global(void);
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 40
+#define MAX_LIBARRAY 41
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index c37e56149eb..3a3be7e82c2 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -100,7 +100,7 @@ typedef enum {
/* For modifiers that use CD_PREVIEW_MCOL for preview. */
eModifierTypeFlag_UsesPreview = (1 << 9),
- eModifierTypeFlag_AcceptsLattice = (1 << 10),
+ eModifierTypeFlag_AcceptsVertexCosOnly = (1 << 10),
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
@@ -211,18 +211,28 @@ typedef struct ModifierTypeInfo {
/********************* Non-deform modifier functions *********************/
- /* For non-deform types: apply the modifier and return a mesh object.
+ /* For non-deform types: apply the modifier and return a mesh datablock.
*
- * The mesh argument should always be non-NULL; the modifier
- * should read the object data from the mesh object instead of the
- * actual object data.
+ * The mesh argument should always be non-NULL; the modifier should use the
+ * passed in mesh datablock rather than object->data, as it contains the mesh
+ * with modifier applied up to this point.
*
- * The modifier may reuse the mesh argument (i.e. return it in
- * modified form), but must not release it.
+ * The modifier may modify and return the mesh argument, but must not free it
+ * and must ensure any referenced data layers are converted to non-referenced
+ * before modification.
*/
- struct Mesh *(*applyModifier)(struct ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct Mesh *mesh);
+ struct Mesh *(*modifyMesh)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Mesh *mesh);
+ struct Hair *(*modifyHair)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Hair *hair);
+ struct PointCloud *(*modifyPointCloud)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct PointCloud *pointcloud);
+ struct Volume *(*modifyVolume)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Volume *volume);
/********************* Optional functions *********************/
@@ -450,9 +460,9 @@ struct ModifierData *modifier_get_evaluated(struct Depsgraph *depsgraph,
/* wrappers for modifier callbacks that ensure valid normals */
-struct Mesh *modwrap_applyModifier(ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct Mesh *me);
+struct Mesh *modwrap_modifyMesh(ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Mesh *me);
void modwrap_deformVerts(ModifierData *md,
const struct ModifierEvalContext *ctx,
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index fe5b8cff31c..927aad287a6 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -110,6 +110,11 @@ void multiresModifier_del_levels(struct MultiresModifierData *mmd,
void multiresModifier_base_apply(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd);
+int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
+ struct Object *object,
+ struct MultiresModifierData *mmd,
+ int rebuild_limit,
+ bool switch_view_to_lower_level);
void multiresModifier_subdivide_legacy(struct MultiresModifierData *mmd,
struct Scene *scene,
struct Object *ob,
@@ -175,13 +180,25 @@ bool multiresModifier_reshapeFromCCG(const int tot_level,
struct SubdivCCG *subdiv_ccg);
/* Subdivide multires displacement once. */
-void multiresModifier_subdivide(struct Object *object, struct MultiresModifierData *mmd);
+
+typedef enum eMultiresSubdivideModeType {
+ MULTIRES_SUBDIVIDE_CATMULL_CLARK,
+ MULTIRES_SUBDIVIDE_SIMPLE,
+ MULTIRES_SUBDIVIDE_LINEAR,
+} eMultiresSubdivideModeType;
+
+void multiresModifier_subdivide(struct Object *object,
+ struct MultiresModifierData *mmd,
+ const eMultiresSubdivideModeType mode);
+void multires_subdivide_create_tangent_displacement_linear_grids(struct Object *object,
+ struct MultiresModifierData *mmd);
/* Subdivide displacement to the given level.
* If level is lower than the current top level nothing happens. */
void multiresModifier_subdivide_to_level(struct Object *object,
struct MultiresModifierData *mmd,
- const int top_level);
+ const int top_level,
+ const eMultiresSubdivideModeType mode);
/* Subdivision integration, defined in multires_subdiv.c */
@@ -213,8 +230,6 @@ BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3]
const float dPdv[3],
const int corner);
-int BKE_multires_sculpt_level_get(const struct MultiresModifierData *mmd);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 38fe974c228..536d04f8bd3 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -385,8 +385,8 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char
/* copy/free funcs, need to manage ID users */
void ntreeFreeTree(struct bNodeTree *ntree);
-/* Free tree which is owned byt another datablock. */
-void ntreeFreeNestedTree(struct bNodeTree *ntree);
+/* Free tree which is embedded into another datablock. */
+void ntreeFreeEmbeddedTree(struct bNodeTree *ntree);
struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree,
struct Main *bmain,
const bool do_id_user);
@@ -852,6 +852,7 @@ struct NodeTreeIterStore {
struct Light *light;
struct World *world;
struct FreestyleLineStyle *linestyle;
+ struct Simulation *simulation;
};
void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain);
@@ -1275,13 +1276,44 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
float dyt[3],
int osatex,
const short thread,
- struct Tex *tex,
+ const struct Tex *tex,
short which_output,
int cfra,
int preview,
struct MTex *mtex);
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Simulation Nodes
+ * \{ */
+
+#define SIM_NODE_PARTICLE_SIMULATION 1000
+#define SIM_NODE_FORCE 1001
+#define SIM_NODE_SET_PARTICLE_ATTRIBUTE 1002
+#define SIM_NODE_PARTICLE_BIRTH_EVENT 1003
+#define SIM_NODE_PARTICLE_TIME_STEP_EVENT 1004
+#define SIM_NODE_EXECUTE_CONDITION 1005
+#define SIM_NODE_MULTI_EXECUTE 1006
+#define SIM_NODE_PARTICLE_MESH_EMITTER 1007
+#define SIM_NODE_PARTICLE_MESH_COLLISION_EVENT 1008
+#define SIM_NODE_EMIT_PARTICLES 1009
+#define SIM_NODE_TIME 1010
+#define SIM_NODE_PARTICLE_ATTRIBUTE 1011
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Function Nodes
+ * \{ */
+
+#define FN_NODE_BOOLEAN_MATH 1200
+#define FN_NODE_SWITCH 1201
+#define FN_NODE_FLOAT_COMPARE 1202
+#define FN_NODE_GROUP_INSTANCE_ID 1203
+#define FN_NODE_COMBINE_STRINGS 1204
+
+/** \} */
+
void init_nodesystem(void);
void free_nodesystem(void);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 94f0e544a6b..35dd241c173 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -48,6 +48,7 @@ struct Mesh;
struct PBVH;
struct PBVHNode;
struct SubdivCCG;
+struct TaskParallelSettings;
struct TaskParallelTLS;
typedef struct PBVH PBVH;
@@ -456,30 +457,10 @@ bool pbvh_has_face_sets(PBVH *bvh);
void pbvh_show_face_sets_set(PBVH *bvh, bool show_face_sets);
/* Parallelization */
-typedef void (*PBVHParallelRangeFunc)(void *__restrict userdata,
- const int iter,
- const struct TaskParallelTLS *__restrict tls);
-typedef void (*PBVHParallelReduceFunc)(const void *__restrict userdata,
- void *__restrict chunk_join,
- void *__restrict chunk);
-
-typedef struct PBVHParallelSettings {
- bool use_threading;
- void *userdata_chunk;
- size_t userdata_chunk_size;
- PBVHParallelReduceFunc func_reduce;
-} PBVHParallelSettings;
-
-void BKE_pbvh_parallel_range_settings(struct PBVHParallelSettings *settings,
+void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings,
bool use_threading,
int totnode);
-void BKE_pbvh_parallel_range(const int start,
- const int stop,
- void *userdata,
- PBVHParallelRangeFunc func,
- const struct PBVHParallelSettings *settings);
-
struct MVert *BKE_pbvh_get_verts(const PBVH *bvh);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 939fcb33b2d..8b7be11e852 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -218,6 +218,15 @@ struct ImBuf *BKE_sequencer_give_ibuf_seqbase(const SeqRenderData *context,
float cfra,
int chan_shown,
struct ListBase *seqbasep);
+struct ImBuf *BKE_sequencer_effect_execute_threaded(struct SeqEffectHandle *sh,
+ const SeqRenderData *context,
+ struct Sequence *seq,
+ float cfra,
+ float facf0,
+ float facf1,
+ struct ImBuf *ibuf1,
+ struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3);
/* **********************************************************************
* sequencer.c
@@ -374,6 +383,10 @@ struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *s
/* intern */
struct SeqEffectHandle BKE_sequence_get_blend(struct Sequence *seq);
void BKE_sequence_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq, bool force);
+float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context,
+ struct Sequence *seq,
+ float cfra,
+ int input);
/* extern */
struct SeqEffectHandle BKE_sequence_get_effect(struct Sequence *seq);
@@ -507,6 +520,7 @@ void BKE_sequence_alpha_mode_from_extension(struct Sequence *seq);
void BKE_sequence_init_colorspace(struct Sequence *seq);
float BKE_sequence_get_fps(struct Scene *scene, struct Sequence *seq);
+float BKE_sequencer_give_stripelem_index(struct Sequence *seq, float cfra);
/* RNA enums, just to be more readable */
enum {
diff --git a/source/blender/blenkernel/BKE_simulation.h b/source/blender/blenkernel/BKE_simulation.h
new file mode 100644
index 00000000000..aad0ada75a9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_simulation.h
@@ -0,0 +1,33 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BKE_SIMULATION_H__
+#define __BKE_SIMULATION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Main;
+struct Simulation;
+
+void *BKE_simulation_add(struct Main *bmain, const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_SIMULATION_H__ */
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 685582bcecf..b93591b7b60 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -164,7 +164,7 @@ void BKE_sound_stop_scene(struct Scene *scene);
void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene);
-float BKE_sound_sync_scene(struct Scene *scene);
+double BKE_sound_sync_scene(struct Scene *scene);
int BKE_sound_scene_playing(struct Scene *scene);
@@ -180,10 +180,10 @@ float BKE_sound_get_length(struct Main *bmain, struct bSound *sound);
char **BKE_sound_get_device_names(void);
-typedef void (*SoundJackSyncCallback)(struct Main *bmain, int mode, float time);
+typedef void (*SoundJackSyncCallback)(struct Main *bmain, int mode, double time);
void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback);
-void BKE_sound_jack_scene_update(struct Scene *scene, int mode, float time);
+void BKE_sound_jack_scene_update(struct Scene *scene, int mode, double time);
/* Dependency graph evaluation. */
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
index 7c7638e65d2..8d2565c31f7 100644
--- a/source/blender/blenkernel/BKE_subdiv_ccg.h
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -40,7 +40,7 @@ struct DMFlagMat;
struct Mesh;
struct Subdiv;
-/* =============================================================================
+/* --------------------------------------------------------------------
* Masks.
*/
@@ -61,7 +61,7 @@ typedef struct SubdivCCGMaskEvaluator {
bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator,
const struct Mesh *mesh);
-/* =============================================================================
+/* --------------------------------------------------------------------
* Materials.
*/
@@ -80,7 +80,7 @@ typedef struct SubdivCCGMaterialFlagsEvaluator {
void BKE_subdiv_ccg_material_flags_init_from_mesh(
SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator, const struct Mesh *mesh);
-/* =============================================================================
+/* --------------------------------------------------------------------
* SubdivCCG.
*/
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 20236745438..bb88fbf863b 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -261,8 +261,16 @@ void BKE_tracking_distortion_undistort_v2(struct MovieDistortion *distortion,
float r_co[2]);
void BKE_tracking_distortion_free(struct MovieDistortion *distortion);
-void BKE_tracking_distort_v2(struct MovieTracking *tracking, const float co[2], float r_co[2]);
-void BKE_tracking_undistort_v2(struct MovieTracking *tracking, const float co[2], float r_co[2]);
+void BKE_tracking_distort_v2(struct MovieTracking *tracking,
+ int image_width,
+ int image_height,
+ const float co[2],
+ float r_co[2]);
+void BKE_tracking_undistort_v2(struct MovieTracking *tracking,
+ int image_width,
+ int image_height,
+ const float co[2],
+ float r_co[2]);
struct ImBuf *BKE_tracking_undistort_frame(struct MovieTracking *tracking,
struct ImBuf *ibuf,
@@ -276,6 +284,8 @@ struct ImBuf *BKE_tracking_distort_frame(struct MovieTracking *tracking,
float overscan);
void BKE_tracking_max_distortion_delta_across_bound(struct MovieTracking *tracking,
+ int image_width,
+ int image_height,
struct rcti *rect,
bool undistort,
float delta[2]);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 6e612df33d5..8e73afea3ac 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -116,6 +116,7 @@ set(SRC
intern/editmesh_tangent.c
intern/effect.c
intern/fcurve.c
+ intern/fcurve_driver.c
intern/fluid.c
intern/fmodifier.c
intern/font.c
@@ -175,9 +176,11 @@ set(SRC
intern/multires_reshape_apply_base.c
intern/multires_reshape_ccg.c
intern/multires_reshape_smooth.c
+ intern/multires_reshape_subdivide.c
intern/multires_reshape_util.c
intern/multires_reshape_vertcos.c
intern/multires_subdiv.c
+ intern/multires_unsubdivide.c
intern/nla.c
intern/node.c
intern/object.c
@@ -197,7 +200,6 @@ set(SRC
intern/particle_system.c
intern/pbvh.c
intern/pbvh_bmesh.c
- intern/pbvh_parallel.cc
intern/pointcache.c
intern/pointcloud.c
intern/report.c
@@ -211,6 +213,7 @@ set(SRC
intern/sequencer.c
intern/shader_fx.c
intern/shrinkwrap.c
+ intern/simulation.cc
intern/softbody.c
intern/sound.c
intern/speaker.c
@@ -299,6 +302,7 @@ set(SRC
BKE_editmesh_tangent.h
BKE_effect.h
BKE_fcurve.h
+ BKE_fcurve_driver.h
BKE_fluid.h
BKE_font.h
BKE_freestyle.h
@@ -362,6 +366,7 @@ set(SRC
BKE_sequencer.h
BKE_shader_fx.h
BKE_shrinkwrap.h
+ BKE_simulation.h
BKE_softbody.h
BKE_sound.h
BKE_speaker.h
@@ -396,6 +401,7 @@ set(SRC
intern/lib_intern.h
intern/multires_inline.h
intern/multires_reshape.h
+ intern/multires_unsubdivide.h
intern/pbvh_intern.h
intern/subdiv_converter.h
intern/subdiv_inline.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index baef2b2290e..b8226c57f80 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -901,16 +901,16 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Sculpt can skip certain modifiers. */
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
- const bool has_multires = (mmd && BKE_multires_sculpt_level_get(mmd) != 0);
+ const bool has_multires = (mmd && mmd->sculptlvl != 0);
bool multires_applied = false;
const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render;
const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render;
/* Modifier evaluation contexts for different types of modifiers. */
- ModifierApplyFlag app_render = use_render ? MOD_APPLY_RENDER : 0;
- ModifierApplyFlag app_cache = use_cache ? MOD_APPLY_USECACHE : 0;
- const ModifierEvalContext mectx = {depsgraph, ob, app_render | app_cache};
- const ModifierEvalContext mectx_orco = {depsgraph, ob, app_render | MOD_APPLY_ORCO};
+ ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : 0;
+ ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : 0;
+ const ModifierEvalContext mectx = {depsgraph, ob, apply_render | apply_cache};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, apply_render | MOD_APPLY_ORCO};
/* Get effective list of modifiers to execute. Some effects like shape keys
* are added as virtual modifiers before the user created modifiers. */
@@ -1020,8 +1020,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
if (sculpt_mode && (!has_multires || multires_applied || sculpt_dyntopo)) {
bool unsupported = false;
- if (md->type == eModifierType_Multires &&
- BKE_multires_sculpt_level_get((MultiresModifierData *)md) == 0) {
+ if (md->type == eModifierType_Multires && ((MultiresModifierData *)md)->sculptlvl == 0) {
/* If multires is on level 0 skip it silently without warning message. */
if (!sculpt_dyntopo) {
continue;
@@ -1176,7 +1175,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final);
+ Mesh *mesh_next = modwrap_modifyMesh(md, &mectx, mesh_final);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1212,7 +1211,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
mesh_set_only_copy(mesh_orco, &temp_cddata_masks);
- mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco);
+ mesh_next = modwrap_modifyMesh(md, &mectx_orco, mesh_orco);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1238,7 +1237,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
nextmask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh_orco_cloth, &nextmask);
- mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco_cloth);
+ mesh_next = modwrap_modifyMesh(md, &mectx_orco, mesh_orco_cloth);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1595,7 +1594,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
mask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh_orco, &mask);
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco);
+ Mesh *mesh_next = modwrap_modifyMesh(md, &mectx_orco, mesh_orco);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1626,7 +1625,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final);
+ Mesh *mesh_next = modwrap_modifyMesh(md, &mectx, mesh_final);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index ba77538bfb6..4f51e23496c 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -1665,6 +1665,6 @@ void what_does_obaction(
adt.action = act;
/* execute effects of Action on to workob (or it's PoseChannels) */
- BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(&workob->id, &adt, cframe, ADT_RECALC_ANIM, false);
}
}
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 41bfc5b59e4..02b7763a9b4 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -29,6 +29,7 @@
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -95,6 +96,7 @@ bool id_type_can_have_animdata(const short id_type)
case ID_HA:
case ID_PT:
case ID_VO:
+ case ID_SIM:
return true;
/* no AnimData */
@@ -1321,6 +1323,9 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
/* volumes */
ANIMDATA_IDS_CB(bmain->volumes.first);
+
+ /* simulations */
+ ANIMDATA_IDS_CB(bmain->simulations.first);
}
/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
@@ -1430,6 +1435,9 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id,
/* volumes */
RENAMEFIX_ANIM_IDS(bmain->volumes.first);
+ /* simulations */
+ RENAMEFIX_ANIM_IDS(bmain->simulations.first);
+
/* scenes */
RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene);
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 18320ef0f8d..5e4b280d0d0 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -2500,7 +2500,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
* have been set already by the depsgraph. Now, we use the recalc
*/
void BKE_animsys_evaluate_animdata(
- Scene *scene, ID *id, AnimData *adt, float ctime, short recalc, const bool flush_to_original)
+ ID *id, AnimData *adt, float ctime, eAnimData_Recalc recalc, const bool flush_to_original)
{
PointerRNA id_ptr;
@@ -2547,13 +2547,6 @@ void BKE_animsys_evaluate_animdata(
* - It is best that we execute this every time, so that no errors are likely to occur.
*/
animsys_evaluate_overrides(&id_ptr, adt);
-
- /* execute and clear all cached property update functions */
- if (scene) {
- Main *bmain = G.main; // xxx - to get passed in!
- RNA_property_update_cache_flush(bmain, scene);
- RNA_property_update_cache_free();
- }
}
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
@@ -2563,10 +2556,7 @@ void BKE_animsys_evaluate_animdata(
* 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
* standard 'root') block are overridden by a larger 'user'
*/
-void BKE_animsys_evaluate_all_animation(Main *main,
- Depsgraph *depsgraph,
- Scene *scene,
- float ctime)
+void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float ctime)
{
ID *id;
@@ -2585,7 +2575,7 @@ void BKE_animsys_evaluate_all_animation(Main *main,
for (id = first; id; id = id->next) { \
if (ID_REAL_USERS(id) > 0) { \
AnimData *adt = BKE_animdata_from_id(id); \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag, flush_to_original); \
+ BKE_animsys_evaluate_animdata(id, adt, ctime, aflag, flush_to_original); \
} \
} \
(void)0
@@ -2604,9 +2594,9 @@ void BKE_animsys_evaluate_all_animation(Main *main,
if (ntp->nodetree) { \
AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
BKE_animsys_evaluate_animdata( \
- scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM, flush_to_original); \
+ &ntp->nodetree->id, adt2, ctime, ADT_RECALC_ANIM, flush_to_original); \
} \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag, flush_to_original); \
+ BKE_animsys_evaluate_animdata(id, adt, ctime, aflag, flush_to_original); \
} \
} \
(void)0
@@ -2690,6 +2680,9 @@ void BKE_animsys_evaluate_all_animation(Main *main,
/* volumes */
EVAL_ANIM_IDS(main->volumes.first, ADT_RECALC_ANIM);
+ /* simulations */
+ EVAL_ANIM_IDS(main->simulations.first, ADT_RECALC_ANIM);
+
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
* this tagged by Depsgraph on framechange. This optimization means that objects
@@ -2718,10 +2711,9 @@ void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id)
AnimData *adt = BKE_animdata_from_id(id);
/* XXX: this is only needed for flushing RNA updates,
* which should get handled as part of the dependency graph instead. */
- Scene *scene = NULL;
DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime);
const bool flush_to_original = DEG_is_active(depsgraph);
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM, flush_to_original);
}
void BKE_animsys_update_driver_array(ID *id)
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 5c000fbcb36..13dcc7b06f6 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -279,9 +279,6 @@ static void setup_app_data(bContext *C,
// CTX_wm_manager_set(C, NULL);
BKE_blender_globals_clear();
- /* clear old property update cache, in case some old references are left dangling */
- RNA_property_update_cache_free();
-
bmain = G_MAIN = bfd->main;
bfd->main = NULL;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 8d35abc1523..f0ea820a1ac 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -49,7 +49,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include "RE_render_ext.h" /* externtex */
+#include "RE_render_ext.h" /* RE_texture_evaluate */
static void brush_init_data(ID *id)
{
@@ -1572,8 +1572,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene,
else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
/* Get strength by feeding the vertex
* location directly into a texture */
- hasrgb = externtex(
- mtex, point, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ hasrgb = RE_texture_evaluate(mtex, point, thread, pool, false, false, &intensity, rgba);
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
float rotation = -mtex->rot;
@@ -1603,8 +1602,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene,
co[1] = y;
co[2] = 0.0f;
- hasrgb = externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
}
else {
float rotation = -mtex->rot;
@@ -1660,8 +1658,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene,
co[1] = y;
co[2] = 0.0f;
- hasrgb = externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
}
intensity += br->texture_sample_bias;
@@ -1718,8 +1715,7 @@ float BKE_brush_sample_masktex(
co[1] = y;
co[2] = 0.0f;
- externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
}
else {
float rotation = -mtex->rot;
@@ -1775,8 +1771,7 @@ float BKE_brush_sample_masktex(
co[1] = y;
co[2] = 0.0f;
- externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
}
CLAMP(intensity, 0.0f, 1.0f);
@@ -2080,7 +2075,7 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
unsigned int *texcache = NULL;
MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex;
float intensity;
- float rgba[4];
+ float rgba_dummy[4];
int ix, iy;
int side = half_side * 2;
@@ -2098,11 +2093,8 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
/* This is copied from displace modifier code */
/* TODO(sergey): brush are always caching with CM enabled for now. */
- externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
-
- ((char *)texcache)[(iy * side + ix) * 4] = ((char *)texcache)[(iy * side + ix) * 4 + 1] =
- ((char *)texcache)[(iy * side + ix) * 4 + 2] = ((
- char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(intensity * 255.0f);
+ RE_texture_evaluate(mtex, co, 0, NULL, false, false, &intensity, rgba_dummy);
+ copy_v4_uchar((uchar *)&texcache[iy * side + ix], (char)(intensity * 255.0f));
}
}
}
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index f82b8b6675c..3da384a2745 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -1383,8 +1383,6 @@ typedef struct ScopesUpdateData {
struct ColormanageProcessor *cm_processor;
const unsigned char *display_buffer;
const int ycc_mode;
-
- unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
} ScopesUpdateData;
typedef struct ScopesUpdateDataChunk {
@@ -1495,23 +1493,24 @@ static void scopes_update_cb(void *__restrict userdata,
}
}
-static void scopes_update_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void scopes_update_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- const ScopesUpdateData *data = userdata;
- const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
-
- unsigned int *bin_lum = data->bin_lum;
- unsigned int *bin_r = data->bin_r;
- unsigned int *bin_g = data->bin_g;
- unsigned int *bin_b = data->bin_b;
- unsigned int *bin_a = data->bin_a;
+ ScopesUpdateDataChunk *join_chunk = chunk_join;
+ const ScopesUpdateDataChunk *data_chunk = chunk;
+
+ unsigned int *bin_lum = join_chunk->bin_lum;
+ unsigned int *bin_r = join_chunk->bin_r;
+ unsigned int *bin_g = join_chunk->bin_g;
+ unsigned int *bin_b = join_chunk->bin_b;
+ unsigned int *bin_a = join_chunk->bin_a;
const unsigned int *bin_lum_c = data_chunk->bin_lum;
const unsigned int *bin_r_c = data_chunk->bin_r;
const unsigned int *bin_g_c = data_chunk->bin_g;
const unsigned int *bin_b_c = data_chunk->bin_b;
const unsigned int *bin_a_c = data_chunk->bin_a;
- float(*minmax)[2] = data->scopes->minmax;
const float *min = data_chunk->min;
const float *max = data_chunk->max;
@@ -1524,11 +1523,11 @@ static void scopes_update_finalize(void *__restrict userdata, void *__restrict u
}
for (int c = 3; c--;) {
- if (min[c] < minmax[c][0]) {
- minmax[c][0] = min[c];
+ if (min[c] < join_chunk->min[c]) {
+ join_chunk->min[c] = min[c];
}
- if (max[c] > minmax[c][1]) {
- minmax[c][1] = max[c];
+ if (max[c] > join_chunk->max[c]) {
+ join_chunk->max[c] = max[c];
}
}
}
@@ -1542,7 +1541,6 @@ void BKE_scopes_update(Scopes *scopes,
unsigned int nl, na, nr, ng, nb;
double divl, diva, divr, divg, divb;
const unsigned char *display_buffer = NULL;
- uint bin_lum[256] = {0}, bin_r[256] = {0}, bin_g[256] = {0}, bin_b[256] = {0}, bin_a[256] = {0};
int ycc_mode = -1;
void *cache_handle = NULL;
struct ColormanageProcessor *cm_processor = NULL;
@@ -1638,11 +1636,6 @@ void BKE_scopes_update(Scopes *scopes,
.cm_processor = cm_processor,
.display_buffer = display_buffer,
.ycc_mode = ycc_mode,
- .bin_lum = bin_lum,
- .bin_r = bin_r,
- .bin_g = bin_g,
- .bin_b = bin_b,
- .bin_a = bin_a,
};
ScopesUpdateDataChunk data_chunk = {{0}};
INIT_MINMAX(data_chunk.min, data_chunk.max);
@@ -1652,26 +1645,26 @@ void BKE_scopes_update(Scopes *scopes,
settings.use_threading = (ibuf->y > 256);
settings.userdata_chunk = &data_chunk;
settings.userdata_chunk_size = sizeof(data_chunk);
- settings.func_finalize = scopes_update_finalize;
+ settings.func_reduce = scopes_update_reduce;
BLI_task_parallel_range(0, ibuf->y, &data, scopes_update_cb, &settings);
/* convert hist data to float (proportional to max count) */
nl = na = nr = nb = ng = 0;
for (a = 0; a < 256; a++) {
- if (bin_lum[a] > nl) {
- nl = bin_lum[a];
+ if (data_chunk.bin_lum[a] > nl) {
+ nl = data_chunk.bin_lum[a];
}
- if (bin_r[a] > nr) {
- nr = bin_r[a];
+ if (data_chunk.bin_r[a] > nr) {
+ nr = data_chunk.bin_r[a];
}
- if (bin_g[a] > ng) {
- ng = bin_g[a];
+ if (data_chunk.bin_g[a] > ng) {
+ ng = data_chunk.bin_g[a];
}
- if (bin_b[a] > nb) {
- nb = bin_b[a];
+ if (data_chunk.bin_b[a] > nb) {
+ nb = data_chunk.bin_b[a];
}
- if (bin_a[a] > na) {
- na = bin_a[a];
+ if (data_chunk.bin_a[a] > na) {
+ na = data_chunk.bin_a[a];
}
}
divl = nl ? 1.0 / (double)nl : 1.0;
@@ -1681,11 +1674,11 @@ void BKE_scopes_update(Scopes *scopes,
divb = nb ? 1.0 / (double)nb : 1.0;
for (a = 0; a < 256; a++) {
- scopes->hist.data_luma[a] = bin_lum[a] * divl;
- scopes->hist.data_r[a] = bin_r[a] * divr;
- scopes->hist.data_g[a] = bin_g[a] * divg;
- scopes->hist.data_b[a] = bin_b[a] * divb;
- scopes->hist.data_a[a] = bin_a[a] * diva;
+ scopes->hist.data_luma[a] = data_chunk.bin_lum[a] * divl;
+ scopes->hist.data_r[a] = data_chunk.bin_r[a] * divr;
+ scopes->hist.data_g[a] = data_chunk.bin_g[a] * divg;
+ scopes->hist.data_b[a] = data_chunk.bin_b[a] * divb;
+ scopes->hist.data_a[a] = data_chunk.bin_a[a] * diva;
}
if (cm_processor) {
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 099fdacf401..3c68753cbf9 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -62,7 +62,7 @@
#include "BKE_deform.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
@@ -1009,8 +1009,8 @@ static void trackto_new_data(void *cdata)
{
bTrackToConstraint *data = (bTrackToConstraint *)cdata;
- data->reserved1 = TRACK_Y;
- data->reserved2 = UP_Z;
+ data->reserved1 = TRACK_nZ;
+ data->reserved2 = UP_Y;
}
static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -4694,7 +4694,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
pos[0] *= width;
pos[1] *= height;
- BKE_tracking_undistort_v2(tracking, pos, pos);
+ BKE_tracking_undistort_v2(tracking, width, height, pos, pos);
/* Normalize pixel coordinates back. */
pos[0] /= width;
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 7ec1da8eab4..3c47615b071 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -386,7 +386,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0);
const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0;
- const bool has_multires = mmd != NULL && BKE_multires_sculpt_level_get(mmd) > 0;
+ const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
if (is_sculpt_mode && has_multires) {
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index b4a8625c0bb..76dec63903b 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -5506,6 +5506,20 @@ void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int
#undef MAT_NR_REMAP
}
+void BKE_curve_smooth_flag_set(Curve *cu, const bool use_smooth)
+{
+ if (use_smooth) {
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ nu->flag |= CU_SMOOTH;
+ }
+ }
+ else {
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ nu->flag &= ~CU_SMOOTH;
+ }
+ }
+}
+
void BKE_curve_rect_from_textbox(const struct Curve *cu,
const struct TextBox *tb,
struct rctf *r_rect)
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 5cb536f98b9..d35dc32738b 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -858,7 +858,7 @@ static bool curve_calc_modifiers_pre(
Curve *cu = ob->data;
int numElems = 0, numVerts = 0;
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
- ModifierApplyFlag app_flag = 0;
+ ModifierApplyFlag apply_flag = 0;
float(*deformedVerts)[3] = NULL;
float *keyVerts = NULL;
int required_mode;
@@ -867,17 +867,17 @@ static bool curve_calc_modifiers_pre(
modifiers_clearErrors(ob);
if (editmode) {
- app_flag |= MOD_APPLY_USECACHE;
+ apply_flag |= MOD_APPLY_USECACHE;
}
if (for_render) {
- app_flag |= MOD_APPLY_RENDER;
+ apply_flag |= MOD_APPLY_RENDER;
required_mode = eModifierMode_Render;
}
else {
required_mode = eModifierMode_Realtime;
}
- const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+ const ModifierEvalContext mectx = {depsgraph, ob, apply_flag};
pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode);
@@ -990,10 +990,10 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
Mesh *modified = NULL, *mesh_applied;
float(*vertCos)[3] = NULL;
int useCache = !for_render;
- ModifierApplyFlag app_flag = 0;
+ ModifierApplyFlag apply_flag = 0;
if (for_render) {
- app_flag |= MOD_APPLY_RENDER;
+ apply_flag |= MOD_APPLY_RENDER;
required_mode = eModifierMode_Render;
}
else {
@@ -1001,9 +1001,9 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
}
const ModifierEvalContext mectx_deform = {
- depsgraph, ob, editmode ? app_flag | MOD_APPLY_USECACHE : app_flag};
+ depsgraph, ob, editmode ? apply_flag | MOD_APPLY_USECACHE : apply_flag};
const ModifierEvalContext mectx_apply = {
- depsgraph, ob, useCache ? app_flag | MOD_APPLY_USECACHE : app_flag};
+ depsgraph, ob, useCache ? apply_flag | MOD_APPLY_USECACHE : apply_flag};
pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode);
@@ -1100,7 +1100,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
if (need_normal) {
BKE_mesh_ensure_normals(modified);
}
- mesh_applied = mti->applyModifier(md, &mectx_apply, modified);
+ mesh_applied = mti->modifyMesh(md, &mectx_apply, modified);
if (mesh_applied) {
/* Modifier returned a new derived mesh */
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index a704e199007..2e1b17844c4 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -653,15 +653,15 @@ static void grid_bound_insert_cb_ex(void *__restrict userdata,
boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
}
-static void grid_bound_insert_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void grid_bound_insert_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
-
- Bounds3D *grid_bound = userdata_chunk;
+ Bounds3D *join = chunk_join;
+ Bounds3D *grid_bound = chunk;
- boundInsert(&grid->grid_bounds, grid_bound->min);
- boundInsert(&grid->grid_bounds, grid_bound->max);
+ boundInsert(join, grid_bound->min);
+ boundInsert(join, grid_bound->max);
}
static void grid_cell_points_cb_ex(void *__restrict userdata,
@@ -685,17 +685,20 @@ static void grid_cell_points_cb_ex(void *__restrict userdata,
s_num[temp_t_index[i]]++;
}
-static void grid_cell_points_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void grid_cell_points_reduce(const void *__restrict userdata,
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
+ const PaintBakeData *bData = userdata;
+ const VolumeGrid *grid = bData->grid;
const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
- int *s_num = userdata_chunk;
+ int *join_s_num = chunk_join;
+ int *s_num = chunk;
/* calculate grid indexes */
for (int i = 0; i < grid_cells; i++) {
- grid->s_num[i] += s_num[i];
+ join_s_num[i] += s_num[i];
}
}
@@ -753,7 +756,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
settings.use_threading = (sData->total_points > 1000);
settings.userdata_chunk = &grid->grid_bounds;
settings.userdata_chunk_size = sizeof(grid->grid_bounds);
- settings.func_finalize = grid_bound_insert_finalize;
+ settings.func_reduce = grid_bound_insert_reduce;
BLI_task_parallel_range(0, sData->total_points, bData, grid_bound_insert_cb_ex, &settings);
}
/* get dimensions */
@@ -814,7 +817,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
settings.use_threading = (sData->total_points > 1000);
settings.userdata_chunk = grid->s_num;
settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells;
- settings.func_finalize = grid_cell_points_finalize;
+ settings.func_reduce = grid_cell_points_reduce;
BLI_task_parallel_range(0, sData->total_points, bData, grid_cell_points_cb_ex, &settings);
}
@@ -4882,7 +4885,7 @@ static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, cons
0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, &settings);
/* calculate average values (single thread).
- * Note: tried to put this in threaded callback (using _finalize feature),
+ * Note: tried to put this in threaded callback (using _reduce feature),
* but gave ~30% slower result! */
bData->average_dist = 0.0;
for (index = 0; index < sData->total_points; index++) {
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
index c3ae2a54e13..6fcaf84d4ca 100644
--- a/source/blender/blenkernel/intern/editmesh_tangent.c
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -251,9 +251,7 @@ finally:
pRes[3] = fSign;
}
-static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
/* new computation method */
@@ -362,9 +360,8 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
#endif
/* Calculation */
if (em->tottri != 0) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL, TASK_PRIORITY_LOW);
+ task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW);
tangent_mask_curr = 0;
/* Calculate tangent layers */
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 439992a4113..543d5c8b7c7 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -30,49 +30,28 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
-#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
-#include "BLI_alloca.h"
#include "BLI_blenlib.h"
#include "BLI_easing.h"
-#include "BLI_expr_pylike_eval.h"
#include "BLI_math.h"
-#include "BLI_string_utils.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-#include "BLT_translation.h"
-
-#include "BKE_action.h"
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
-#include "BKE_armature.h"
-#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_nla.h"
-#include "BKE_object.h"
#include "RNA_access.h"
-#include "atomic_ops.h"
-
#include "CLG_log.h"
-#ifdef WITH_PYTHON
-# include "BPY_extern.h"
-#endif
-
#define SMALL -1.0e-10
#define SELECT 1
-#ifdef WITH_PYTHON
-static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER;
-#endif
-
static CLG_LogRef LOG = {"bke.fcurve"};
/* ************************** Data-Level Functions ************************* */
@@ -1256,1236 +1235,6 @@ short test_time_fcurve(FCurve *fcu)
return 0;
}
-/* ***************************** Drivers ********************************* */
-
-/* Driver Variables --------------------------- */
-
-/* TypeInfo for Driver Variables (dvti) */
-typedef struct DriverVarTypeInfo {
- /* evaluation callback */
- float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
-
- /* allocation of target slots */
- int num_targets; /* number of target slots required */
- const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
- short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
-} DriverVarTypeInfo;
-
-/* Macro to begin definitions */
-#define BEGIN_DVAR_TYPEDEF(type) {
-
-/* Macro to end definitions */
-#define END_DVAR_TYPEDEF }
-
-/* ......... */
-
-static ID *dtar_id_ensure_proxy_from(ID *id)
-{
- if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from) {
- return (ID *)(((Object *)id)->proxy_from);
- }
- return id;
-}
-
-/**
- * Helper function to obtain a value using RNA from the specified source
- * (for evaluating drivers).
- */
-static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
-{
- PointerRNA id_ptr, ptr;
- PropertyRNA *prop;
- ID *id;
- int index = -1;
- float value = 0.0f;
-
- /* sanity check */
- if (ELEM(NULL, driver, dtar)) {
- return 0.0f;
- }
-
- id = dtar_id_ensure_proxy_from(dtar->id);
-
- /* error check for missing pointer... */
- if (id == NULL) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
-
- /* get RNA-pointer for the ID-block given in target */
- RNA_id_pointer_create(id, &id_ptr);
-
- /* get property to read from, and get value as appropriate */
- if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
- /* path couldn't be resolved */
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG,
- "Driver Evaluation Error: cannot resolve target for %s -> %s",
- id->name,
- dtar->rna_path);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
-
- if (RNA_property_array_check(prop)) {
- /* array */
- if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) {
- /* out of bounds */
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG,
- "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
- id->name,
- dtar->rna_path,
- index);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
-
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- value = (float)RNA_property_boolean_get_index(&ptr, prop, index);
- break;
- case PROP_INT:
- value = (float)RNA_property_int_get_index(&ptr, prop, index);
- break;
- case PROP_FLOAT:
- value = RNA_property_float_get_index(&ptr, prop, index);
- break;
- default:
- break;
- }
- }
- else {
- /* not an array */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- value = (float)RNA_property_boolean_get(&ptr, prop);
- break;
- case PROP_INT:
- value = (float)RNA_property_int_get(&ptr, prop);
- break;
- case PROP_FLOAT:
- value = RNA_property_float_get(&ptr, prop);
- break;
- case PROP_ENUM:
- value = (float)RNA_property_enum_get(&ptr, prop);
- break;
- default:
- break;
- }
- }
-
- /* if we're still here, we should be ok... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- return value;
-}
-
-/**
- * Same as 'dtar_get_prop_val'. but get the RNA property.
- */
-bool driver_get_variable_property(ChannelDriver *driver,
- DriverTarget *dtar,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop,
- int *r_index)
-{
- PointerRNA id_ptr;
- PointerRNA ptr;
- PropertyRNA *prop;
- ID *id;
- int index = -1;
-
- /* sanity check */
- if (ELEM(NULL, driver, dtar)) {
- return false;
- }
-
- id = dtar_id_ensure_proxy_from(dtar->id);
-
- /* error check for missing pointer... */
- if (id == NULL) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return false;
- }
-
- /* get RNA-pointer for the ID-block given in target */
- RNA_id_pointer_create(id, &id_ptr);
-
- /* get property to read from, and get value as appropriate */
- if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
- ptr = PointerRNA_NULL;
- prop = NULL; /* ok */
- }
- else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
- /* ok */
- }
- else {
- /* path couldn't be resolved */
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG,
- "Driver Evaluation Error: cannot resolve target for %s -> %s",
- id->name,
- dtar->rna_path);
- }
-
- ptr = PointerRNA_NULL;
- *r_prop = NULL;
- *r_index = -1;
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return false;
- }
-
- *r_ptr = ptr;
- *r_prop = prop;
- *r_index = index;
-
- /* if we're still here, we should be ok... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- return true;
-}
-
-static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
-{
- short valid_targets = 0;
-
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
-
- /* check if this target has valid data */
- if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- }
- else {
- /* target seems to be OK now... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- valid_targets++;
- }
- }
- DRIVER_TARGETS_LOOPER_END;
-
- return valid_targets;
-}
-
-/* ......... */
-
-/* evaluate 'single prop' driver variable */
-static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
-{
- /* just evaluate the first target slot */
- return dtar_get_prop_val(driver, &dvar->targets[0]);
-}
-
-/* evaluate 'rotation difference' driver variable */
-static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
-{
- short valid_targets = driver_check_valid_targets(driver, dvar);
-
- /* make sure we have enough valid targets to use - all or nothing for now... */
- if (driver_check_valid_targets(driver, dvar) != 2) {
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG,
- "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
- valid_targets,
- dvar->targets[0].id,
- dvar->targets[1].id);
- }
- return 0.0f;
- }
-
- float(*mat[2])[4];
-
- /* NOTE: for now, these are all just worldspace */
- for (int i = 0; i < 2; i++) {
- /* get pointer to loc values to store in */
- DriverTarget *dtar = &dvar->targets[i];
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
-
- /* after the checks above, the targets should be valid here... */
- BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
-
- /* try to get posechannel */
- pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
-
- /* check if object or bone */
- if (pchan) {
- /* bone */
- mat[i] = pchan->pose_mat;
- }
- else {
- /* object */
- mat[i] = ob->obmat;
- }
- }
-
- float q1[4], q2[4], quat[4], angle;
-
- /* use the final posed locations */
- mat4_to_quat(q1, mat[0]);
- mat4_to_quat(q2, mat[1]);
-
- invert_qt_normalized(q1);
- mul_qt_qtqt(quat, q1, q2);
- angle = 2.0f * (saacos(quat[0]));
- angle = fabsf(angle);
-
- return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
-}
-
-/* evaluate 'location difference' driver variable */
-/* TODO: this needs to take into account space conversions... */
-static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
-{
- float loc1[3] = {0.0f, 0.0f, 0.0f};
- float loc2[3] = {0.0f, 0.0f, 0.0f};
- short valid_targets = driver_check_valid_targets(driver, dvar);
-
- /* make sure we have enough valid targets to use - all or nothing for now... */
- if (valid_targets < dvar->num_targets) {
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG,
- "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
- valid_targets,
- dvar->targets[0].id,
- dvar->targets[1].id);
- }
- return 0.0f;
- }
-
- /* SECOND PASS: get two location values */
- /* NOTE: for now, these are all just worldspace */
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- /* get pointer to loc values to store in */
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
- float tmp_loc[3];
-
- /* after the checks above, the targets should be valid here... */
- BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
-
- /* try to get posechannel */
- pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
-
- /* check if object or bone */
- if (pchan) {
- /* bone */
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- float mat[4][4];
-
- /* extract transform just like how the constraints do it! */
- copy_m4_m4(mat, pchan->pose_mat);
- BKE_constraint_mat_convertspace(
- ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
-
- /* ... and from that, we get our transform */
- copy_v3_v3(tmp_loc, mat[3]);
- }
- else {
- /* transform space (use transform values directly) */
- copy_v3_v3(tmp_loc, pchan->loc);
- }
- }
- else {
- /* convert to worldspace */
- copy_v3_v3(tmp_loc, pchan->pose_head);
- mul_m4_v3(ob->obmat, tmp_loc);
- }
- }
- else {
- /* object */
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* XXX: this should practically be the same as transform space... */
- float mat[4][4];
-
- /* extract transform just like how the constraints do it! */
- copy_m4_m4(mat, ob->obmat);
- BKE_constraint_mat_convertspace(
- ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
-
- /* ... and from that, we get our transform */
- copy_v3_v3(tmp_loc, mat[3]);
- }
- else {
- /* transform space (use transform values directly) */
- copy_v3_v3(tmp_loc, ob->loc);
- }
- }
- else {
- /* worldspace */
- copy_v3_v3(tmp_loc, ob->obmat[3]);
- }
- }
-
- /* copy the location to the right place */
- if (tarIndex) {
- copy_v3_v3(loc2, tmp_loc);
- }
- else {
- copy_v3_v3(loc1, tmp_loc);
- }
- }
- DRIVER_TARGETS_LOOPER_END;
-
- /* if we're still here, there should now be two targets to use,
- * so just take the length of the vector between these points
- */
- return len_v3v3(loc1, loc2);
-}
-
-/* evaluate 'transform channel' driver variable */
-static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
-{
- DriverTarget *dtar = &dvar->targets[0];
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
- float mat[4][4];
- float oldEul[3] = {0.0f, 0.0f, 0.0f};
- bool use_eulers = false;
- short rot_order = ROT_MODE_EUL;
-
- /* check if this target has valid data */
- if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
- else {
- /* target should be valid now */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- }
-
- /* try to get posechannel */
- pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
-
- /* check if object or bone, and get transform matrix accordingly
- * - "useEulers" code is used to prevent the problems associated with non-uniqueness
- * of euler decomposition from matrices [#20870]
- * - localspace is for [#21384], where parent results are not wanted
- * but local-consts is for all the common "corrective-shapes-for-limbs" situations
- */
- if (pchan) {
- /* bone */
- if (pchan->rotmode > 0) {
- copy_v3_v3(oldEul, pchan->eul);
- rot_order = pchan->rotmode;
- use_eulers = true;
- }
-
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* just like how the constraints do it! */
- copy_m4_m4(mat, pchan->pose_mat);
- BKE_constraint_mat_convertspace(
- ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
- }
- else {
- /* specially calculate local matrix, since chan_mat is not valid
- * since it stores delta transform of pose_mat so that deforms work
- * so it cannot be used here for "transform" space
- */
- BKE_pchan_to_mat4(pchan, mat);
- }
- }
- else {
- /* worldspace matrix */
- mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
- }
- }
- else {
- /* object */
- if (ob->rotmode > 0) {
- copy_v3_v3(oldEul, ob->rot);
- rot_order = ob->rotmode;
- use_eulers = true;
- }
-
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* just like how the constraints do it! */
- copy_m4_m4(mat, ob->obmat);
- BKE_constraint_mat_convertspace(
- ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
- }
- else {
- /* transforms to matrix */
- BKE_object_to_mat4(ob, mat);
- }
- }
- else {
- /* worldspace matrix - just the good-old one */
- copy_m4_m4(mat, ob->obmat);
- }
- }
-
- /* check which transform */
- if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) {
- /* not valid channel */
- return 0.0f;
- }
- else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) {
- /* Cubic root of the change in volume, equal to the geometric mean
- * of scale over all three axes unless the matrix includes shear. */
- return cbrtf(mat4_to_volume_scale(mat));
- }
- else if (ELEM(dtar->transChan,
- DTAR_TRANSCHAN_SCALEX,
- DTAR_TRANSCHAN_SCALEY,
- DTAR_TRANSCHAN_SCALEZ)) {
- /* Extract scale, and choose the right axis,
- * inline 'mat4_to_size'. */
- return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
- }
- else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
- /* extract rotation as eulers (if needed)
- * - definitely if rotation order isn't eulers already
- * - if eulers, then we have 2 options:
- * a) decompose transform matrix as required, then try to make eulers from
- * there compatible with original values
- * b) [NOT USED] directly use the original values (no decomposition)
- * - only an option for "transform space", if quality is really bad with a)
- */
- float quat[4];
- int channel;
-
- if (dtar->transChan == DTAR_TRANSCHAN_ROTW) {
- channel = 0;
- }
- else {
- channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX;
- BLI_assert(channel < 4);
- }
-
- BKE_driver_target_matrix_to_rot_channels(
- mat, rot_order, dtar->rotation_mode, channel, false, quat);
-
- if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) {
- compatible_eul(quat + 1, oldEul);
- }
-
- return quat[channel];
- }
- else {
- /* extract location and choose right axis */
- return mat[3][dtar->transChan];
- }
-}
-
-/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */
-static void quaternion_to_angles(float quat[4], int channel)
-{
- if (channel < 0) {
- quat[0] = 2.0f * saacosf(quat[0]);
-
- for (int i = 1; i < 4; i++) {
- quat[i] = 2.0f * saasinf(quat[i]);
- }
- }
- else if (channel == 0) {
- quat[0] = 2.0f * saacosf(quat[0]);
- }
- else {
- quat[channel] = 2.0f * saasinf(quat[channel]);
- }
-}
-
-/* Compute channel values for a rotational Transform Channel driver variable. */
-void BKE_driver_target_matrix_to_rot_channels(
- float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4])
-{
- float *const quat = r_buf;
- float *const eul = r_buf + 1;
-
- zero_v4(r_buf);
-
- if (rotation_mode == DTAR_ROTMODE_AUTO) {
- mat4_to_eulO(eul, auto_order, mat);
- }
- else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) {
- mat4_to_eulO(eul, rotation_mode, mat);
- }
- else if (rotation_mode == DTAR_ROTMODE_QUATERNION) {
- mat4_to_quat(quat, mat);
-
- /* For Transformation constraint convenience, convert to pseudo-angles. */
- if (angles) {
- quaternion_to_angles(quat, channel);
- }
- }
- else if (rotation_mode >= DTAR_ROTMODE_SWING_TWIST_X &&
- rotation_mode <= DTAR_ROTMODE_SWING_TWIST_Z) {
- int axis = rotation_mode - DTAR_ROTMODE_SWING_TWIST_X;
- float raw_quat[4], twist;
-
- mat4_to_quat(raw_quat, mat);
-
- if (channel == axis + 1) {
- /* If only the twist angle is needed, skip computing swing. */
- twist = quat_split_swing_and_twist(raw_quat, axis, NULL, NULL);
- }
- else {
- twist = quat_split_swing_and_twist(raw_quat, axis, quat, NULL);
-
- quaternion_to_angles(quat, channel);
- }
-
- quat[axis + 1] = twist;
- }
- else {
- BLI_assert(false);
- }
-}
-
-/* ......... */
-
-/* Table of Driver Variable Type Info Data */
-static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */
- 1, /* number of targets used */
- {"Property"}, /* UI names for targets */
- {0} /* flags */
- END_DVAR_TYPEDEF,
-
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */
- 2, /* number of targets used */
- {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
- {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
- DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
- END_DVAR_TYPEDEF,
-
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */
- 2, /* number of targets used */
- {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
- {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
- DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
- END_DVAR_TYPEDEF,
-
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */
- 1, /* number of targets used */
- {"Object/Bone"}, /* UI names for targets */
- {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
- END_DVAR_TYPEDEF,
-};
-
-/* Get driver variable typeinfo */
-static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
-{
- /* check if valid type */
- if ((type >= 0) && (type < MAX_DVAR_TYPES)) {
- return &dvar_types[type];
- }
- else {
- return NULL;
- }
-}
-
-/* Driver API --------------------------------- */
-
-/* Perform actual freeing driver variable and remove it from the given list */
-void driver_free_variable(ListBase *variables, DriverVar *dvar)
-{
- /* sanity checks */
- if (dvar == NULL) {
- return;
- }
-
- /* free target vars
- * - need to go over all of them, not just up to the ones that are used
- * currently, since there may be some lingering RNA paths from
- * previous users needing freeing
- */
- DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
- /* free RNA path if applicable */
- if (dtar->rna_path) {
- MEM_freeN(dtar->rna_path);
- }
- }
- DRIVER_TARGETS_LOOPER_END;
-
- /* remove the variable from the driver */
- BLI_freelinkN(variables, dvar);
-}
-
-/* Free the driver variable and do extra updates */
-void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
-{
- /* remove and free the driver variable */
- driver_free_variable(&driver->variables, dvar);
-
- /* since driver variables are cached, the expression needs re-compiling too */
- BKE_driver_invalidate_expression(driver, false, true);
-}
-
-/* Copy driver variables from src_vars list to dst_vars list */
-void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
-{
- BLI_assert(BLI_listbase_is_empty(dst_vars));
- BLI_duplicatelist(dst_vars, src_vars);
-
- LISTBASE_FOREACH (DriverVar *, dvar, dst_vars) {
- /* need to go over all targets so that we don't leave any dangling paths */
- DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
- /* make a copy of target's rna path if available */
- if (dtar->rna_path) {
- dtar->rna_path = MEM_dupallocN(dtar->rna_path);
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
-}
-
-/* Change the type of driver variable */
-void driver_change_variable_type(DriverVar *dvar, int type)
-{
- const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
-
- /* sanity check */
- if (ELEM(NULL, dvar, dvti)) {
- return;
- }
-
- /* set the new settings */
- dvar->type = type;
- dvar->num_targets = dvti->num_targets;
-
- /* make changes to the targets based on the defines for these types
- * NOTE: only need to make sure the ones we're using here are valid...
- */
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- short flags = dvti->target_flags[tarIndex];
-
- /* store the flags */
- dtar->flag = flags;
-
- /* object ID types only, or idtype not yet initialized */
- if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) {
- dtar->idtype = ID_OB;
- }
- }
- DRIVER_TARGETS_LOOPER_END;
-}
-
-/* Validate driver name (after being renamed) */
-void driver_variable_name_validate(DriverVar *dvar)
-{
- /* Special character blacklist */
- const char special_char_blacklist[] = {
- '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-', '/', '\\',
- '?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r',
- };
-
- /* sanity checks */
- if (dvar == NULL) {
- return;
- }
-
- /* clear all invalid-name flags */
- dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
-
- /* 0) Zero-length identifiers are not allowed */
- if (dvar->name[0] == '\0') {
- dvar->flag |= DVAR_FLAG_INVALID_EMPTY;
- }
-
- /* 1) Must start with a letter */
- /* XXX: We assume that valid unicode letters in other languages are ok too,
- * hence the blacklisting. */
- if (IN_RANGE_INCL(dvar->name[0], '0', '9')) {
- dvar->flag |= DVAR_FLAG_INVALID_START_NUM;
- }
- else if (dvar->name[0] == '_') {
- /* NOTE: We don't allow names to start with underscores
- * (i.e. it helps when ruling out security risks) */
- dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
- }
-
- /* 2) Must not contain invalid stuff in the middle of the string */
- if (strchr(dvar->name, ' ')) {
- dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE;
- }
- if (strchr(dvar->name, '.')) {
- dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT;
- }
-
- /* 3) Check for special characters - Either at start, or in the middle */
- for (int i = 0; i < sizeof(special_char_blacklist); i++) {
- char *match = strchr(dvar->name, special_char_blacklist[i]);
-
- if (match == dvar->name) {
- dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
- }
- else if (match != NULL) {
- dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL;
- }
- }
-
- /* 4) Check if the name is a reserved keyword
- * NOTE: These won't confuse Python, but it will be impossible to use the variable
- * in an expression without Python misinterpreting what these are for
- */
-#ifdef WITH_PYTHON
- if (BPY_string_is_keyword(dvar->name)) {
- dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD;
- }
-#endif
-
- /* If any these conditions match, the name is invalid */
- if (dvar->flag & DVAR_ALL_INVALID_FLAGS) {
- dvar->flag |= DVAR_FLAG_INVALID_NAME;
- }
-}
-
-/* Add a new driver variable */
-DriverVar *driver_add_new_variable(ChannelDriver *driver)
-{
- DriverVar *dvar;
-
- /* sanity checks */
- if (driver == NULL) {
- return NULL;
- }
-
- /* make a new variable */
- dvar = MEM_callocN(sizeof(DriverVar), "DriverVar");
- BLI_addtail(&driver->variables, dvar);
-
- /* give the variable a 'unique' name */
- strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
- BLI_uniquename(&driver->variables,
- dvar,
- CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"),
- '_',
- offsetof(DriverVar, name),
- sizeof(dvar->name));
-
- /* set the default type to 'single prop' */
- driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
-
- /* since driver variables are cached, the expression needs re-compiling too */
- BKE_driver_invalidate_expression(driver, false, true);
-
- /* return the target */
- return dvar;
-}
-
-/* This frees the driver itself */
-void fcurve_free_driver(FCurve *fcu)
-{
- ChannelDriver *driver;
- DriverVar *dvar, *dvarn;
-
- /* sanity checks */
- if (ELEM(NULL, fcu, fcu->driver)) {
- return;
- }
- driver = fcu->driver;
-
- /* free driver targets */
- for (dvar = driver->variables.first; dvar; dvar = dvarn) {
- dvarn = dvar->next;
- driver_free_variable_ex(driver, dvar);
- }
-
-#ifdef WITH_PYTHON
- /* free compiled driver expression */
- if (driver->expr_comp) {
- BPY_DECREF(driver->expr_comp);
- }
-#endif
-
- BLI_expr_pylike_free(driver->expr_simple);
-
- /* Free driver itself, then set F-Curve's point to this to NULL
- * (as the curve may still be used). */
- MEM_freeN(driver);
- fcu->driver = NULL;
-}
-
-/* This makes a copy of the given driver */
-ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
-{
- ChannelDriver *ndriver;
-
- /* sanity checks */
- if (driver == NULL) {
- return NULL;
- }
-
- /* copy all data */
- ndriver = MEM_dupallocN(driver);
- ndriver->expr_comp = NULL;
- ndriver->expr_simple = NULL;
-
- /* copy variables */
-
- /* to get rid of refs to non-copied data (that's still used on original) */
- BLI_listbase_clear(&ndriver->variables);
- driver_variables_copy(&ndriver->variables, &driver->variables);
-
- /* return the new driver */
- return ndriver;
-}
-
-/* Driver Expression Evaluation --------------- */
-
-/* Index constants for the expression parameter array. */
-enum {
- /* Index of the 'frame' variable. */
- VAR_INDEX_FRAME = 0,
- /* Index of the first user-defined driver variable. */
- VAR_INDEX_CUSTOM
-};
-
-static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver)
-{
- /* Prepare parameter names. */
- int names_len = BLI_listbase_count(&driver->variables);
- const char **names = BLI_array_alloca(names, names_len + VAR_INDEX_CUSTOM);
- int i = VAR_INDEX_CUSTOM;
-
- names[VAR_INDEX_FRAME] = "frame";
-
- LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
- names[i++] = dvar->name;
- }
-
- return BLI_expr_pylike_parse(driver->expression, names, names_len + VAR_INDEX_CUSTOM);
-}
-
-static bool driver_check_simple_expr_depends_on_time(ExprPyLike_Parsed *expr)
-{
- /* Check if the 'frame' parameter is actually used. */
- return BLI_expr_pylike_is_using_param(expr, VAR_INDEX_FRAME);
-}
-
-static bool driver_evaluate_simple_expr(ChannelDriver *driver,
- ExprPyLike_Parsed *expr,
- float *result,
- float time)
-{
- /* Prepare parameter values. */
- int vars_len = BLI_listbase_count(&driver->variables);
- double *vars = BLI_array_alloca(vars, vars_len + VAR_INDEX_CUSTOM);
- int i = VAR_INDEX_CUSTOM;
-
- vars[VAR_INDEX_FRAME] = time;
-
- LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
- vars[i++] = driver_get_variable_value(driver, dvar);
- }
-
- /* Evaluate expression. */
- double result_val;
- eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(
- expr, vars, vars_len + VAR_INDEX_CUSTOM, &result_val);
- const char *message;
-
- switch (status) {
- case EXPR_PYLIKE_SUCCESS:
- if (isfinite(result_val)) {
- *result = (float)result_val;
- }
- return true;
-
- case EXPR_PYLIKE_DIV_BY_ZERO:
- case EXPR_PYLIKE_MATH_ERROR:
- message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error";
- CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression);
-
- driver->flag |= DRIVER_FLAG_INVALID;
- return true;
-
- default:
- /* arriving here means a bug, not user error */
- CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression);
- return false;
- }
-}
-
-/* Compile and cache the driver expression if necessary, with thread safety. */
-static bool driver_compile_simple_expr(ChannelDriver *driver)
-{
- if (driver->expr_simple != NULL) {
- return true;
- }
-
- if (driver->type != DRIVER_TYPE_PYTHON) {
- return false;
- }
-
- /* It's safe to parse in multiple threads; at worst it'll
- * waste some effort, but in return avoids mutex contention. */
- ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver);
-
- /* Store the result if the field is still NULL, or discard
- * it if another thread got here first. */
- if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) {
- BLI_expr_pylike_free(expr);
- }
-
- return true;
-}
-
-/* Try using the simple expression evaluator to compute the result of the driver.
- * On success, stores the result and returns true; on failure result is set to 0. */
-static bool driver_try_evaluate_simple_expr(ChannelDriver *driver,
- ChannelDriver *driver_orig,
- float *result,
- float time)
-{
- *result = 0.0f;
-
- return driver_compile_simple_expr(driver_orig) &&
- BLI_expr_pylike_is_valid(driver_orig->expr_simple) &&
- driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
-}
-
-/* Check if the expression in the driver conforms to the simple subset. */
-bool BKE_driver_has_simple_expression(ChannelDriver *driver)
-{
- return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
-}
-
-/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive
- * time dependencies nor special exceptions in the depsgraph evaluation. */
-static bool python_driver_exression_depends_on_time(const char *expression)
-{
- if (expression[0] == '\0') {
- /* Empty expression depends on nothing. */
- return false;
- }
- if (strchr(expression, '(') != NULL) {
- /* Function calls are considered dependent on a time. */
- return true;
- }
- if (strstr(expression, "frame") != NULL) {
- /* Variable `frame` depends on time. */
- /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */
- return true;
- }
- /* Possible indirect time relation s should be handled via variable targets. */
- return false;
-}
-
-/* Check if the expression in the driver may depend on the current frame. */
-bool BKE_driver_expression_depends_on_time(ChannelDriver *driver)
-{
- if (driver->type != DRIVER_TYPE_PYTHON) {
- return false;
- }
-
- if (BKE_driver_has_simple_expression(driver)) {
- /* Simple expressions can be checked exactly. */
- return driver_check_simple_expr_depends_on_time(driver->expr_simple);
- }
- else {
- /* Otherwise, heuristically scan the expression string for certain patterns. */
- return python_driver_exression_depends_on_time(driver->expression);
- }
-}
-
-/* Reset cached compiled expression data */
-void BKE_driver_invalidate_expression(ChannelDriver *driver,
- bool expr_changed,
- bool varname_changed)
-{
- if (expr_changed || varname_changed) {
- BLI_expr_pylike_free(driver->expr_simple);
- driver->expr_simple = NULL;
- }
-
-#ifdef WITH_PYTHON
- if (expr_changed) {
- driver->flag |= DRIVER_FLAG_RECOMPILE;
- }
-
- if (varname_changed) {
- driver->flag |= DRIVER_FLAG_RENAMEVAR;
- }
-#endif
-}
-
-/* Driver Evaluation -------------------------- */
-
-/* Evaluate a Driver Variable to get a value that contributes to the final */
-float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
-{
- const DriverVarTypeInfo *dvti;
-
- /* sanity check */
- if (ELEM(NULL, driver, dvar)) {
- return 0.0f;
- }
-
- /* call the relevant callbacks to get the variable value
- * using the variable type info, storing the obtained value
- * in dvar->curval so that drivers can be debugged
- */
- dvti = get_dvar_typeinfo(dvar->type);
-
- if (dvti && dvti->get_value) {
- dvar->curval = dvti->get_value(driver, dvar);
- }
- else {
- dvar->curval = 0.0f;
- }
-
- return dvar->curval;
-}
-
-static void evaluate_driver_sum(ChannelDriver *driver)
-{
- DriverVar *dvar;
-
- /* check how many variables there are first (i.e. just one?) */
- if (BLI_listbase_is_single(&driver->variables)) {
- /* just one target, so just use that */
- dvar = driver->variables.first;
- driver->curval = driver_get_variable_value(driver, dvar);
- return;
- }
-
- /* more than one target, so average the values of the targets */
- float value = 0.0f;
- int tot = 0;
-
- /* loop through targets, adding (hopefully we don't get any overflow!) */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- value += driver_get_variable_value(driver, dvar);
- tot++;
- }
-
- /* perform operations on the total if appropriate */
- if (driver->type == DRIVER_TYPE_AVERAGE) {
- driver->curval = tot ? (value / (float)tot) : 0.0f;
- }
- else {
- driver->curval = value;
- }
-}
-
-static void evaluate_driver_min_max(ChannelDriver *driver)
-{
- DriverVar *dvar;
- float value = 0.0f;
-
- /* loop through the variables, getting the values and comparing them to existing ones */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* get value */
- float tmp_val = driver_get_variable_value(driver, dvar);
-
- /* store this value if appropriate */
- if (dvar->prev) {
- /* check if greater/smaller than the baseline */
- if (driver->type == DRIVER_TYPE_MAX) {
- /* max? */
- if (tmp_val > value) {
- value = tmp_val;
- }
- }
- else {
- /* min? */
- if (tmp_val < value) {
- value = tmp_val;
- }
- }
- }
- else {
- /* first item - make this the baseline for comparisons */
- value = tmp_val;
- }
- }
-
- /* store value in driver */
- driver->curval = value;
-}
-
-static void evaluate_driver_python(PathResolvedRNA *anim_rna,
- ChannelDriver *driver,
- ChannelDriver *driver_orig,
- const float evaltime)
-{
- /* check for empty or invalid expression */
- if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) {
- driver->curval = 0.0f;
- }
- else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) {
-#ifdef WITH_PYTHON
- /* this evaluates the expression using Python, and returns its result:
- * - on errors it reports, then returns 0.0f
- */
- BLI_mutex_lock(&python_driver_lock);
-
- driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime);
-
- BLI_mutex_unlock(&python_driver_lock);
-#else /* WITH_PYTHON*/
- UNUSED_VARS(anim_rna, evaltime);
-#endif /* WITH_PYTHON*/
- }
-}
-
-/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
- * - "evaltime" is the frame at which F-Curve is being evaluated
- * - has to return a float value
- * - driver_orig is where we cache Python expressions, in case of COW
- */
-float evaluate_driver(PathResolvedRNA *anim_rna,
- ChannelDriver *driver,
- ChannelDriver *driver_orig,
- const float evaltime)
-{
- /* check if driver can be evaluated */
- if (driver_orig->flag & DRIVER_FLAG_INVALID) {
- return 0.0f;
- }
-
- switch (driver->type) {
- case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
- case DRIVER_TYPE_SUM: /* sum values of driver targets */
- evaluate_driver_sum(driver);
- break;
- case DRIVER_TYPE_MIN: /* smallest value */
- case DRIVER_TYPE_MAX: /* largest value */
- evaluate_driver_min_max(driver);
- break;
- case DRIVER_TYPE_PYTHON: /* expression */
- evaluate_driver_python(anim_rna, driver, driver_orig, evaltime);
- break;
- default:
- /* special 'hack' - just use stored value
- * This is currently used as the mechanism which allows animated settings to be able
- * to be changed via the UI.
- */
- break;
- }
-
- /* return value for driver */
- return driver->curval;
-}
-
/* ***************************** Curve Calculations ********************************* */
/* The total length of the handles is not allowed to be more
@@ -2666,437 +1415,327 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
/* -------------------------- */
-/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */
-static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime)
+static float fcurve_eval_keyframes_extrapolate(
+ FCurve *fcu, BezTriple *bezts, float evaltime, int endpoint_offset, int direction_to_neighbor)
+{
+ BezTriple *endpoint_bezt = bezts + endpoint_offset; /* The first/last keyframe. */
+ BezTriple *neighbor_bezt = endpoint_bezt +
+ direction_to_neighbor; /* The second (to last) keyframe. */
+
+ if (endpoint_bezt->ipo == BEZT_IPO_CONST || fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT ||
+ (fcu->flag & FCURVE_DISCRETE_VALUES) != 0) {
+ /* Constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, so just extend the
+ * endpoint's value. */
+ return endpoint_bezt->vec[1][1];
+ }
+
+ if (endpoint_bezt->ipo == BEZT_IPO_LIN) {
+ /* Use the next center point instead of our own handle for linear interpolated extrapolate. */
+ if (fcu->totvert == 1) {
+ return endpoint_bezt->vec[1][1];
+ }
+
+ float dx = endpoint_bezt->vec[1][0] - evaltime;
+ float fac = neighbor_bezt->vec[1][0] - endpoint_bezt->vec[1][0];
+
+ /* Prevent division by zero. */
+ if (fac == 0.0f) {
+ return endpoint_bezt->vec[1][1];
+ }
+
+ fac = (neighbor_bezt->vec[1][1] - endpoint_bezt->vec[1][1]) / fac;
+ return endpoint_bezt->vec[1][1] - (fac * dx);
+ }
+
+ /* Use the gradient of the second handle (later) of neighbour to calculate the gradient and thus
+ * the value of the curve at evaltime */
+ int handle = direction_to_neighbor > 0 ? 0 : 2;
+ float dx = endpoint_bezt->vec[1][0] - evaltime;
+ float fac = endpoint_bezt->vec[1][0] - endpoint_bezt->vec[handle][0];
+
+ /* Prevent division by zero. */
+ if (fac == 0.0f) {
+ return endpoint_bezt->vec[1][1];
+ }
+
+ fac = (endpoint_bezt->vec[1][1] - endpoint_bezt->vec[handle][1]) / fac;
+ return endpoint_bezt->vec[1][1] - (fac * dx);
+}
+
+static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, float evaltime)
{
const float eps = 1.e-8f;
- BezTriple *bezt, *prevbezt, *lastbezt;
- float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac;
+ BezTriple *bezt, *prevbezt;
unsigned int a;
- int b;
- float cvalue = 0.0f;
- /* get pointers */
- a = fcu->totvert - 1;
- prevbezt = bezts;
- bezt = prevbezt + 1;
- lastbezt = prevbezt + a;
+ /* evaltime occurs somewhere in the middle of the curve */
+ bool exact = false;
+
+ /* Use binary search to find appropriate keyframes...
+ *
+ * The threshold here has the following constraints:
+ * - 0.001 is too coarse:
+ * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332)
+ *
+ * - 0.00001 is too fine:
+ * Weird errors, like selecting the wrong keyframe range (see T39207), occur.
+ * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd.
+ */
+ a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact);
+ bezt = bezts + a;
- /* evaluation time at or past endpoints? */
- if (prevbezt->vec[1][0] >= evaltime) {
- /* before or on first keyframe */
- if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST) &&
- !(fcu->flag & FCURVE_DISCRETE_VALUES)) {
- /* linear or bezier interpolation */
- if (prevbezt->ipo == BEZT_IPO_LIN) {
- /* Use the next center point instead of our own handle for
- * linear interpolated extrapolate
- */
- if (fcu->totvert == 1) {
- cvalue = prevbezt->vec[1][1];
- }
- else {
- bezt = prevbezt + 1;
- dx = prevbezt->vec[1][0] - evaltime;
- fac = bezt->vec[1][0] - prevbezt->vec[1][0];
-
- /* prevent division by zero */
- if (fac) {
- fac = (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
- cvalue = prevbezt->vec[1][1] - (fac * dx);
- }
- else {
- cvalue = prevbezt->vec[1][1];
- }
- }
- }
- else {
- /* Use the first handle (earlier) of first BezTriple to calculate the
- * gradient and thus the value of the curve at evaltime
- */
- dx = prevbezt->vec[1][0] - evaltime;
- fac = prevbezt->vec[1][0] - prevbezt->vec[0][0];
+ if (exact) {
+ /* index returned must be interpreted differently when it sits on top of an existing keyframe
+ * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207)
+ */
+ return bezt->vec[1][1];
+ }
- /* prevent division by zero */
- if (fac) {
- fac = (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac;
- cvalue = prevbezt->vec[1][1] - (fac * dx);
- }
- else {
- cvalue = prevbezt->vec[1][1];
- }
- }
- }
- else {
- /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
- * so just extend first keyframe's value
- */
- cvalue = prevbezt->vec[1][1];
+ /* index returned refers to the keyframe that the eval-time occurs *before*
+ * - hence, that keyframe marks the start of the segment we're dealing with
+ */
+ prevbezt = (a > 0) ? (bezt - 1) : bezt;
+
+ /* Use if the key is directly on the frame, in rare cases this is needed else we get 0.0 instead.
+ * XXX: consult T39207 for examples of files where failure of these checks can cause issues */
+ if (fabsf(bezt->vec[1][0] - evaltime) < eps) {
+ return bezt->vec[1][1];
+ }
+
+ if (evaltime < prevbezt->vec[1][0] || bezt->vec[1][0] < evaltime) {
+ if (G.debug & G_DEBUG) {
+ printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n",
+ prevbezt->vec[1][0],
+ bezt->vec[1][0],
+ evaltime,
+ fabsf(bezt->vec[1][0] - evaltime));
}
+ return 0.0f;
}
- else if (lastbezt->vec[1][0] <= evaltime) {
- /* after or on last keyframe */
- if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST) &&
- !(fcu->flag & FCURVE_DISCRETE_VALUES)) {
- /* linear or bezier interpolation */
- if (lastbezt->ipo == BEZT_IPO_LIN) {
- /* Use the next center point instead of our own handle for
- * linear interpolated extrapolate
+
+ /* Evaltime occurs within the interval defined by these two keyframes. */
+ const float begin = prevbezt->vec[1][1];
+ const float change = bezt->vec[1][1] - prevbezt->vec[1][1];
+ const float duration = bezt->vec[1][0] - prevbezt->vec[1][0];
+ const float time = evaltime - prevbezt->vec[1][0];
+ const float amplitude = prevbezt->amplitude;
+ const float period = prevbezt->period;
+
+ /* value depends on interpolation mode */
+ if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) ||
+ (duration == 0)) {
+ /* constant (evaltime not relevant, so no interpolation needed) */
+ return prevbezt->vec[1][1];
+ }
+
+ switch (prevbezt->ipo) {
+ /* interpolation ...................................... */
+ case BEZT_IPO_BEZ: {
+ float v1[2], v2[2], v3[2], v4[2], opl[32];
+
+ /* bezier interpolation */
+ /* (v1, v2) are the first keyframe and its 2nd handle */
+ v1[0] = prevbezt->vec[1][0];
+ v1[1] = prevbezt->vec[1][1];
+ v2[0] = prevbezt->vec[2][0];
+ v2[1] = prevbezt->vec[2][1];
+ /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */
+ v3[0] = bezt->vec[0][0];
+ v3[1] = bezt->vec[0][1];
+ v4[0] = bezt->vec[1][0];
+ v4[1] = bezt->vec[1][1];
+
+ if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON &&
+ fabsf(v3[1] - v4[1]) < FLT_EPSILON) {
+ /* Optimization: If all the handles are flat/at the same values,
+ * the value is simply the shared value (see T40372 -> F91346)
*/
- if (fcu->totvert == 1) {
- cvalue = lastbezt->vec[1][1];
- }
- else {
- prevbezt = lastbezt - 1;
- dx = evaltime - lastbezt->vec[1][0];
- fac = lastbezt->vec[1][0] - prevbezt->vec[1][0];
-
- /* prevent division by zero */
- if (fac) {
- fac = (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
- cvalue = lastbezt->vec[1][1] + (fac * dx);
- }
- else {
- cvalue = lastbezt->vec[1][1];
- }
+ return v1[1];
+ }
+ /* adjust handles so that they don't overlap (forming a loop) */
+ correct_bezpart(v1, v2, v3, v4);
+
+ /* try to get a value for this position - if failure, try another set of points */
+ if (!findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl)) {
+ if (G.debug & G_DEBUG) {
+ printf(" ERROR: findzero() failed at %f with %f %f %f %f\n",
+ evaltime,
+ v1[0],
+ v2[0],
+ v3[0],
+ v4[0]);
}
+ return 0.0;
}
- else {
- /* Use the gradient of the second handle (later) of last BezTriple to calculate the
- * gradient and thus the value of the curve at evaltime
- */
- dx = evaltime - lastbezt->vec[1][0];
- fac = lastbezt->vec[2][0] - lastbezt->vec[1][0];
- /* prevent division by zero */
- if (fac) {
- fac = (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac;
- cvalue = lastbezt->vec[1][1] + (fac * dx);
- }
- else {
- cvalue = lastbezt->vec[1][1];
- }
+ berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
+ return opl[0];
+ }
+ case BEZT_IPO_LIN:
+ /* linear - simply linearly interpolate between values of the two keyframes */
+ return BLI_easing_linear_ease(time, begin, change, duration);
+
+ /* easing ............................................ */
+ case BEZT_IPO_BACK:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back);
+
+ default: /* default/auto: same as ease out */
+ return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
}
- }
- else {
- /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
- * so just extend last keyframe's value
- */
- cvalue = lastbezt->vec[1][1];
- }
- }
- else {
- /* evaltime occurs somewhere in the middle of the curve */
- bool exact = false;
-
- /* Use binary search to find appropriate keyframes...
- *
- * The threshold here has the following constraints:
- * - 0.001 is too coarse:
- * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332)
- *
- * - 0.00001 is too fine:
- * Weird errors, like selecting the wrong keyframe range (see T39207), occur.
- * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd.
- */
- a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact);
+ break;
- if (exact) {
- /* index returned must be interpreted differently when it sits on top of an existing keyframe
- * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207)
- */
- prevbezt = bezts + a;
- bezt = (a < fcu->totvert - 1) ? (prevbezt + 1) : prevbezt;
- }
- else {
- /* index returned refers to the keyframe that the eval-time occurs *before*
- * - hence, that keyframe marks the start of the segment we're dealing with
- */
- bezt = bezts + a;
- prevbezt = (a > 0) ? (bezt - 1) : bezt;
- }
+ case BEZT_IPO_BOUNCE:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_bounce_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_bounce_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_bounce_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease out */
+ return BLI_easing_bounce_ease_out(time, begin, change, duration);
+ }
+ break;
- /* use if the key is directly on the frame,
- * rare cases this is needed else we get 0.0 instead. */
- /* XXX: consult T39207 for examples of files where failure of these checks can cause issues */
- if (exact) {
- cvalue = prevbezt->vec[1][1];
- }
- else if (fabsf(bezt->vec[1][0] - evaltime) < eps) {
- cvalue = bezt->vec[1][1];
- }
- /* evaltime occurs within the interval defined by these two keyframes */
- else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) {
- const float begin = prevbezt->vec[1][1];
- const float change = bezt->vec[1][1] - prevbezt->vec[1][1];
- const float duration = bezt->vec[1][0] - prevbezt->vec[1][0];
- const float time = evaltime - prevbezt->vec[1][0];
- const float amplitude = prevbezt->amplitude;
- const float period = prevbezt->period;
-
- /* value depends on interpolation mode */
- if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) ||
- (duration == 0)) {
- /* constant (evaltime not relevant, so no interpolation needed) */
- cvalue = prevbezt->vec[1][1];
+ case BEZT_IPO_CIRC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_circ_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_circ_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_circ_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_circ_ease_in(time, begin, change, duration);
}
- else {
- switch (prevbezt->ipo) {
- /* interpolation ...................................... */
- case BEZT_IPO_BEZ:
- /* bezier interpolation */
- /* (v1, v2) are the first keyframe and its 2nd handle */
- v1[0] = prevbezt->vec[1][0];
- v1[1] = prevbezt->vec[1][1];
- v2[0] = prevbezt->vec[2][0];
- v2[1] = prevbezt->vec[2][1];
- /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */
- v3[0] = bezt->vec[0][0];
- v3[1] = bezt->vec[0][1];
- v4[0] = bezt->vec[1][0];
- v4[1] = bezt->vec[1][1];
-
- if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON &&
- fabsf(v3[1] - v4[1]) < FLT_EPSILON) {
- /* Optimization: If all the handles are flat/at the same values,
- * the value is simply the shared value (see T40372 -> F91346)
- */
- cvalue = v1[1];
- }
- else {
- /* adjust handles so that they don't overlap (forming a loop) */
- correct_bezpart(v1, v2, v3, v4);
-
- /* try to get a value for this position - if failure, try another set of points */
- b = findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl);
- if (b) {
- berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
- cvalue = opl[0];
- /* break; */
- }
- else {
- if (G.debug & G_DEBUG) {
- printf(" ERROR: findzero() failed at %f with %f %f %f %f\n",
- evaltime,
- v1[0],
- v2[0],
- v3[0],
- v4[0]);
- }
- }
- }
- break;
-
- case BEZT_IPO_LIN:
- /* linear - simply linearly interpolate between values of the two keyframes */
- cvalue = BLI_easing_linear_ease(time, begin, change, duration);
- break;
-
- /* easing ............................................ */
- case BEZT_IPO_BACK:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_back_ease_in_out(
- time, begin, change, duration, prevbezt->back);
- break;
-
- default: /* default/auto: same as ease out */
- cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
- break;
- }
- break;
-
- case BEZT_IPO_BOUNCE:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_bounce_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_bounce_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease out */
- cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_CIRC:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_circ_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_circ_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_circ_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_circ_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_CUBIC:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_cubic_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_cubic_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_ELASTIC:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_elastic_ease_in(
- time, begin, change, duration, amplitude, period);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_elastic_ease_out(
- time, begin, change, duration, amplitude, period);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_elastic_ease_in_out(
- time, begin, change, duration, amplitude, period);
- break;
-
- default: /* default/auto: same as ease out */
- cvalue = BLI_easing_elastic_ease_out(
- time, begin, change, duration, amplitude, period);
- break;
- }
- break;
-
- case BEZT_IPO_EXPO:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_expo_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_expo_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_expo_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_expo_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_QUAD:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_quad_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_quad_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_quad_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_quad_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_QUART:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_quart_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_quart_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_quart_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_quart_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_QUINT:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_quint_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_quint_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_quint_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_quint_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_SINE:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_sine_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_sine_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_sine_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_sine_ease_in(time, begin, change, duration);
- break;
- }
- break;
+ break;
- default:
- cvalue = prevbezt->vec[1][1];
- break;
- }
+ case BEZT_IPO_CUBIC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_cubic_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_cubic_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_cubic_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_cubic_ease_in(time, begin, change, duration);
}
- }
- else {
- if (G.debug & G_DEBUG) {
- printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n",
- prevbezt->vec[1][0],
- bezt->vec[1][0],
- evaltime,
- fabsf(bezt->vec[1][0] - evaltime));
+ break;
+
+ case BEZT_IPO_ELASTIC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
+
+ default: /* default/auto: same as ease out */
+ return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
}
- }
+ break;
+
+ case BEZT_IPO_EXPO:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_expo_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_expo_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_expo_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_expo_ease_in(time, begin, change, duration);
+ }
+ break;
+
+ case BEZT_IPO_QUAD:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_quad_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_quad_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_quad_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_quad_ease_in(time, begin, change, duration);
+ }
+ break;
+
+ case BEZT_IPO_QUART:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_quart_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_quart_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_quart_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_quart_ease_in(time, begin, change, duration);
+ }
+ break;
+
+ case BEZT_IPO_QUINT:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_quint_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_quint_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_quint_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_quint_ease_in(time, begin, change, duration);
+ }
+ break;
+
+ case BEZT_IPO_SINE:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_sine_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_sine_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_sine_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_sine_ease_in(time, begin, change, duration);
+ }
+ break;
+
+ default:
+ return prevbezt->vec[1][1];
}
- /* return value */
- return cvalue;
+ return 0.0f;
+}
+
+/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */
+static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime)
+{
+ if (evaltime <= bezts->vec[1][0]) {
+ return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1);
+ }
+
+ BezTriple *lastbezt = bezts + fcu->totvert - 1;
+ if (lastbezt->vec[1][0] <= evaltime) {
+ return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1);
+ }
+
+ return fcurve_eval_keyframes_interpolate(fcu, bezts, evaltime);
}
/* Calculate F-Curve value for 'evaltime' using FPoint samples */
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
new file mode 100644
index 00000000000..78a6cf28824
--- /dev/null
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -0,0 +1,1294 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+// #include <float.h>
+// #include <math.h>
+// #include <stddef.h>
+// #include <stdio.h>
+// #include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_expr_pylike_eval.h"
+#include "BLI_math.h"
+#include "BLI_string_utils.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_fcurve_driver.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+
+#include "RNA_access.h"
+
+#include "atomic_ops.h"
+
+#include "CLG_log.h"
+
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+#ifdef WITH_PYTHON
+static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER;
+#endif
+
+static CLG_LogRef LOG = {"bke.fcurve"};
+
+/* Driver Variables --------------------------- */
+
+/* TypeInfo for Driver Variables (dvti) */
+typedef struct DriverVarTypeInfo {
+ /* evaluation callback */
+ float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
+
+ /* allocation of target slots */
+ int num_targets; /* number of target slots required */
+ const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
+ short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
+} DriverVarTypeInfo;
+
+/* Macro to begin definitions */
+#define BEGIN_DVAR_TYPEDEF(type) {
+
+/* Macro to end definitions */
+#define END_DVAR_TYPEDEF }
+
+/* ......... */
+
+static ID *dtar_id_ensure_proxy_from(ID *id)
+{
+ if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from) {
+ return (ID *)(((Object *)id)->proxy_from);
+ }
+ return id;
+}
+
+/**
+ * Helper function to obtain a value using RNA from the specified source
+ * (for evaluating drivers).
+ */
+static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
+{
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ ID *id;
+ int index = -1;
+ float value = 0.0f;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dtar)) {
+ return 0.0f;
+ }
+
+ id = dtar_id_ensure_proxy_from(dtar->id);
+
+ /* error check for missing pointer... */
+ if (id == NULL) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+
+ /* get RNA-pointer for the ID-block given in target */
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
+ /* path couldn't be resolved */
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "Driver Evaluation Error: cannot resolve target for %s -> %s",
+ id->name,
+ dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+
+ if (RNA_property_array_check(prop)) {
+ /* array */
+ if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) {
+ /* out of bounds */
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
+ id->name,
+ dtar->rna_path,
+ index);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ value = (float)RNA_property_boolean_get_index(&ptr, prop, index);
+ break;
+ case PROP_INT:
+ value = (float)RNA_property_int_get_index(&ptr, prop, index);
+ break;
+ case PROP_FLOAT:
+ value = RNA_property_float_get_index(&ptr, prop, index);
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ /* not an array */
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ value = (float)RNA_property_boolean_get(&ptr, prop);
+ break;
+ case PROP_INT:
+ value = (float)RNA_property_int_get(&ptr, prop);
+ break;
+ case PROP_FLOAT:
+ value = RNA_property_float_get(&ptr, prop);
+ break;
+ case PROP_ENUM:
+ value = (float)RNA_property_enum_get(&ptr, prop);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* if we're still here, we should be ok... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ return value;
+}
+
+/**
+ * Same as 'dtar_get_prop_val'. but get the RNA property.
+ */
+bool driver_get_variable_property(ChannelDriver *driver,
+ DriverTarget *dtar,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index)
+{
+ PointerRNA id_ptr;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ID *id;
+ int index = -1;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dtar)) {
+ return false;
+ }
+
+ id = dtar_id_ensure_proxy_from(dtar->id);
+
+ /* error check for missing pointer... */
+ if (id == NULL) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return false;
+ }
+
+ /* get RNA-pointer for the ID-block given in target */
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
+ ptr = PointerRNA_NULL;
+ prop = NULL; /* ok */
+ }
+ else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
+ /* ok */
+ }
+ else {
+ /* path couldn't be resolved */
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "Driver Evaluation Error: cannot resolve target for %s -> %s",
+ id->name,
+ dtar->rna_path);
+ }
+
+ ptr = PointerRNA_NULL;
+ *r_prop = NULL;
+ *r_index = -1;
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return false;
+ }
+
+ *r_ptr = ptr;
+ *r_prop = prop;
+ *r_index = index;
+
+ /* if we're still here, we should be ok... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ return true;
+}
+
+static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
+{
+ short valid_targets = 0;
+
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+
+ /* check if this target has valid data */
+ if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
+ /* invalid target, so will not have enough targets */
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ }
+ else {
+ /* target seems to be OK now... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ valid_targets++;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+
+ return valid_targets;
+}
+
+/* ......... */
+
+/* evaluate 'single prop' driver variable */
+static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
+{
+ /* just evaluate the first target slot */
+ return dtar_get_prop_val(driver, &dvar->targets[0]);
+}
+
+/* evaluate 'rotation difference' driver variable */
+static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
+{
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (driver_check_valid_targets(driver, dvar) != 2) {
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG,
+ "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
+ valid_targets,
+ dvar->targets[0].id,
+ dvar->targets[1].id);
+ }
+ return 0.0f;
+ }
+
+ float(*mat[2])[4];
+
+ /* NOTE: for now, these are all just worldspace */
+ for (int i = 0; i < 2; i++) {
+ /* get pointer to loc values to store in */
+ DriverTarget *dtar = &dvar->targets[i];
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone */
+ if (pchan) {
+ /* bone */
+ mat[i] = pchan->pose_mat;
+ }
+ else {
+ /* object */
+ mat[i] = ob->obmat;
+ }
+ }
+
+ float q1[4], q2[4], quat[4], angle;
+
+ /* use the final posed locations */
+ mat4_to_quat(q1, mat[0]);
+ mat4_to_quat(q2, mat[1]);
+
+ invert_qt_normalized(q1);
+ mul_qt_qtqt(quat, q1, q2);
+ angle = 2.0f * (saacos(quat[0]));
+ angle = fabsf(angle);
+
+ return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
+}
+
+/* evaluate 'location difference' driver variable */
+/* TODO: this needs to take into account space conversions... */
+static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
+{
+ float loc1[3] = {0.0f, 0.0f, 0.0f};
+ float loc2[3] = {0.0f, 0.0f, 0.0f};
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (valid_targets < dvar->num_targets) {
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG,
+ "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
+ valid_targets,
+ dvar->targets[0].id,
+ dvar->targets[1].id);
+ }
+ return 0.0f;
+ }
+
+ /* SECOND PASS: get two location values */
+ /* NOTE: for now, these are all just worldspace */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ /* get pointer to loc values to store in */
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+ float tmp_loc[3];
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone */
+ if (pchan) {
+ /* bone */
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ float mat[4][4];
+
+ /* extract transform just like how the constraints do it! */
+ copy_m4_m4(mat, pchan->pose_mat);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
+
+ /* ... and from that, we get our transform */
+ copy_v3_v3(tmp_loc, mat[3]);
+ }
+ else {
+ /* transform space (use transform values directly) */
+ copy_v3_v3(tmp_loc, pchan->loc);
+ }
+ }
+ else {
+ /* convert to worldspace */
+ copy_v3_v3(tmp_loc, pchan->pose_head);
+ mul_m4_v3(ob->obmat, tmp_loc);
+ }
+ }
+ else {
+ /* object */
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ /* XXX: this should practically be the same as transform space... */
+ float mat[4][4];
+
+ /* extract transform just like how the constraints do it! */
+ copy_m4_m4(mat, ob->obmat);
+ BKE_constraint_mat_convertspace(
+ ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
+
+ /* ... and from that, we get our transform */
+ copy_v3_v3(tmp_loc, mat[3]);
+ }
+ else {
+ /* transform space (use transform values directly) */
+ copy_v3_v3(tmp_loc, ob->loc);
+ }
+ }
+ else {
+ /* worldspace */
+ copy_v3_v3(tmp_loc, ob->obmat[3]);
+ }
+ }
+
+ /* copy the location to the right place */
+ if (tarIndex) {
+ copy_v3_v3(loc2, tmp_loc);
+ }
+ else {
+ copy_v3_v3(loc1, tmp_loc);
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+
+ /* if we're still here, there should now be two targets to use,
+ * so just take the length of the vector between these points
+ */
+ return len_v3v3(loc1, loc2);
+}
+
+/* evaluate 'transform channel' driver variable */
+static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
+{
+ DriverTarget *dtar = &dvar->targets[0];
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+ float mat[4][4];
+ float oldEul[3] = {0.0f, 0.0f, 0.0f};
+ bool use_eulers = false;
+ short rot_order = ROT_MODE_EUL;
+
+ /* check if this target has valid data */
+ if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
+ /* invalid target, so will not have enough targets */
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+ else {
+ /* target should be valid now */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ }
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone, and get transform matrix accordingly
+ * - "useEulers" code is used to prevent the problems associated with non-uniqueness
+ * of euler decomposition from matrices [#20870]
+ * - localspace is for [#21384], where parent results are not wanted
+ * but local-consts is for all the common "corrective-shapes-for-limbs" situations
+ */
+ if (pchan) {
+ /* bone */
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(oldEul, pchan->eul);
+ rot_order = pchan->rotmode;
+ use_eulers = true;
+ }
+
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ /* just like how the constraints do it! */
+ copy_m4_m4(mat, pchan->pose_mat);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
+ }
+ else {
+ /* specially calculate local matrix, since chan_mat is not valid
+ * since it stores delta transform of pose_mat so that deforms work
+ * so it cannot be used here for "transform" space
+ */
+ BKE_pchan_to_mat4(pchan, mat);
+ }
+ }
+ else {
+ /* worldspace matrix */
+ mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
+ }
+ }
+ else {
+ /* object */
+ if (ob->rotmode > 0) {
+ copy_v3_v3(oldEul, ob->rot);
+ rot_order = ob->rotmode;
+ use_eulers = true;
+ }
+
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ /* just like how the constraints do it! */
+ copy_m4_m4(mat, ob->obmat);
+ BKE_constraint_mat_convertspace(
+ ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
+ }
+ else {
+ /* transforms to matrix */
+ BKE_object_to_mat4(ob, mat);
+ }
+ }
+ else {
+ /* worldspace matrix - just the good-old one */
+ copy_m4_m4(mat, ob->obmat);
+ }
+ }
+
+ /* check which transform */
+ if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) {
+ /* not valid channel */
+ return 0.0f;
+ }
+ else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) {
+ /* Cubic root of the change in volume, equal to the geometric mean
+ * of scale over all three axes unless the matrix includes shear. */
+ return cbrtf(mat4_to_volume_scale(mat));
+ }
+ else if (ELEM(dtar->transChan,
+ DTAR_TRANSCHAN_SCALEX,
+ DTAR_TRANSCHAN_SCALEY,
+ DTAR_TRANSCHAN_SCALEZ)) {
+ /* Extract scale, and choose the right axis,
+ * inline 'mat4_to_size'. */
+ return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
+ }
+ else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
+ /* extract rotation as eulers (if needed)
+ * - definitely if rotation order isn't eulers already
+ * - if eulers, then we have 2 options:
+ * a) decompose transform matrix as required, then try to make eulers from
+ * there compatible with original values
+ * b) [NOT USED] directly use the original values (no decomposition)
+ * - only an option for "transform space", if quality is really bad with a)
+ */
+ float quat[4];
+ int channel;
+
+ if (dtar->transChan == DTAR_TRANSCHAN_ROTW) {
+ channel = 0;
+ }
+ else {
+ channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX;
+ BLI_assert(channel < 4);
+ }
+
+ BKE_driver_target_matrix_to_rot_channels(
+ mat, rot_order, dtar->rotation_mode, channel, false, quat);
+
+ if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) {
+ compatible_eul(quat + 1, oldEul);
+ }
+
+ return quat[channel];
+ }
+ else {
+ /* extract location and choose right axis */
+ return mat[3][dtar->transChan];
+ }
+}
+
+/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */
+static void quaternion_to_angles(float quat[4], int channel)
+{
+ if (channel < 0) {
+ quat[0] = 2.0f * saacosf(quat[0]);
+
+ for (int i = 1; i < 4; i++) {
+ quat[i] = 2.0f * saasinf(quat[i]);
+ }
+ }
+ else if (channel == 0) {
+ quat[0] = 2.0f * saacosf(quat[0]);
+ }
+ else {
+ quat[channel] = 2.0f * saasinf(quat[channel]);
+ }
+}
+
+/* Compute channel values for a rotational Transform Channel driver variable. */
+void BKE_driver_target_matrix_to_rot_channels(
+ float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4])
+{
+ float *const quat = r_buf;
+ float *const eul = r_buf + 1;
+
+ zero_v4(r_buf);
+
+ if (rotation_mode == DTAR_ROTMODE_AUTO) {
+ mat4_to_eulO(eul, auto_order, mat);
+ }
+ else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) {
+ mat4_to_eulO(eul, rotation_mode, mat);
+ }
+ else if (rotation_mode == DTAR_ROTMODE_QUATERNION) {
+ mat4_to_quat(quat, mat);
+
+ /* For Transformation constraint convenience, convert to pseudo-angles. */
+ if (angles) {
+ quaternion_to_angles(quat, channel);
+ }
+ }
+ else if (rotation_mode >= DTAR_ROTMODE_SWING_TWIST_X &&
+ rotation_mode <= DTAR_ROTMODE_SWING_TWIST_Z) {
+ int axis = rotation_mode - DTAR_ROTMODE_SWING_TWIST_X;
+ float raw_quat[4], twist;
+
+ mat4_to_quat(raw_quat, mat);
+
+ if (channel == axis + 1) {
+ /* If only the twist angle is needed, skip computing swing. */
+ twist = quat_split_swing_and_twist(raw_quat, axis, NULL, NULL);
+ }
+ else {
+ twist = quat_split_swing_and_twist(raw_quat, axis, quat, NULL);
+
+ quaternion_to_angles(quat, channel);
+ }
+
+ quat[axis + 1] = twist;
+ }
+ else {
+ BLI_assert(false);
+ }
+}
+
+/* ......... */
+
+/* Table of Driver Variable Type Info Data */
+static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */
+ 1, /* number of targets used */
+ {"Property"}, /* UI names for targets */
+ {0} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */
+ 2, /* number of targets used */
+ {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
+ DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */
+ 2, /* number of targets used */
+ {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
+ DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */
+ 1, /* number of targets used */
+ {"Object/Bone"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF,
+};
+
+/* Get driver variable typeinfo */
+static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
+{
+ /* check if valid type */
+ if ((type >= 0) && (type < MAX_DVAR_TYPES)) {
+ return &dvar_types[type];
+ }
+ else {
+ return NULL;
+ }
+}
+
+/* Driver API --------------------------------- */
+
+/* Perform actual freeing driver variable and remove it from the given list */
+void driver_free_variable(ListBase *variables, DriverVar *dvar)
+{
+ /* sanity checks */
+ if (dvar == NULL) {
+ return;
+ }
+
+ /* free target vars
+ * - need to go over all of them, not just up to the ones that are used
+ * currently, since there may be some lingering RNA paths from
+ * previous users needing freeing
+ */
+ DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
+ /* free RNA path if applicable */
+ if (dtar->rna_path) {
+ MEM_freeN(dtar->rna_path);
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+
+ /* remove the variable from the driver */
+ BLI_freelinkN(variables, dvar);
+}
+
+/* Free the driver variable and do extra updates */
+void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
+{
+ /* remove and free the driver variable */
+ driver_free_variable(&driver->variables, dvar);
+
+ /* since driver variables are cached, the expression needs re-compiling too */
+ BKE_driver_invalidate_expression(driver, false, true);
+}
+
+/* Copy driver variables from src_vars list to dst_vars list */
+void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
+{
+ BLI_assert(BLI_listbase_is_empty(dst_vars));
+ BLI_duplicatelist(dst_vars, src_vars);
+
+ LISTBASE_FOREACH (DriverVar *, dvar, dst_vars) {
+ /* need to go over all targets so that we don't leave any dangling paths */
+ DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
+ /* make a copy of target's rna path if available */
+ if (dtar->rna_path) {
+ dtar->rna_path = MEM_dupallocN(dtar->rna_path);
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+}
+
+/* Change the type of driver variable */
+void driver_change_variable_type(DriverVar *dvar, int type)
+{
+ const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
+
+ /* sanity check */
+ if (ELEM(NULL, dvar, dvti)) {
+ return;
+ }
+
+ /* set the new settings */
+ dvar->type = type;
+ dvar->num_targets = dvti->num_targets;
+
+ /* make changes to the targets based on the defines for these types
+ * NOTE: only need to make sure the ones we're using here are valid...
+ */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ short flags = dvti->target_flags[tarIndex];
+
+ /* store the flags */
+ dtar->flag = flags;
+
+ /* object ID types only, or idtype not yet initialized */
+ if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) {
+ dtar->idtype = ID_OB;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+}
+
+/* Validate driver name (after being renamed) */
+void driver_variable_name_validate(DriverVar *dvar)
+{
+ /* Special character blacklist */
+ const char special_char_blacklist[] = {
+ '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-', '/', '\\',
+ '?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r',
+ };
+
+ /* sanity checks */
+ if (dvar == NULL) {
+ return;
+ }
+
+ /* clear all invalid-name flags */
+ dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
+
+ /* 0) Zero-length identifiers are not allowed */
+ if (dvar->name[0] == '\0') {
+ dvar->flag |= DVAR_FLAG_INVALID_EMPTY;
+ }
+
+ /* 1) Must start with a letter */
+ /* XXX: We assume that valid unicode letters in other languages are ok too,
+ * hence the blacklisting. */
+ if (IN_RANGE_INCL(dvar->name[0], '0', '9')) {
+ dvar->flag |= DVAR_FLAG_INVALID_START_NUM;
+ }
+ else if (dvar->name[0] == '_') {
+ /* NOTE: We don't allow names to start with underscores
+ * (i.e. it helps when ruling out security risks) */
+ dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
+ }
+
+ /* 2) Must not contain invalid stuff in the middle of the string */
+ if (strchr(dvar->name, ' ')) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE;
+ }
+ if (strchr(dvar->name, '.')) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT;
+ }
+
+ /* 3) Check for special characters - Either at start, or in the middle */
+ for (int i = 0; i < sizeof(special_char_blacklist); i++) {
+ char *match = strchr(dvar->name, special_char_blacklist[i]);
+
+ if (match == dvar->name) {
+ dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
+ }
+ else if (match != NULL) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL;
+ }
+ }
+
+ /* 4) Check if the name is a reserved keyword
+ * NOTE: These won't confuse Python, but it will be impossible to use the variable
+ * in an expression without Python misinterpreting what these are for
+ */
+#ifdef WITH_PYTHON
+ if (BPY_string_is_keyword(dvar->name)) {
+ dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD;
+ }
+#endif
+
+ /* If any these conditions match, the name is invalid */
+ if (dvar->flag & DVAR_ALL_INVALID_FLAGS) {
+ dvar->flag |= DVAR_FLAG_INVALID_NAME;
+ }
+}
+
+/* Add a new driver variable */
+DriverVar *driver_add_new_variable(ChannelDriver *driver)
+{
+ DriverVar *dvar;
+
+ /* sanity checks */
+ if (driver == NULL) {
+ return NULL;
+ }
+
+ /* make a new variable */
+ dvar = MEM_callocN(sizeof(DriverVar), "DriverVar");
+ BLI_addtail(&driver->variables, dvar);
+
+ /* give the variable a 'unique' name */
+ strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
+ BLI_uniquename(&driver->variables,
+ dvar,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"),
+ '_',
+ offsetof(DriverVar, name),
+ sizeof(dvar->name));
+
+ /* set the default type to 'single prop' */
+ driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
+
+ /* since driver variables are cached, the expression needs re-compiling too */
+ BKE_driver_invalidate_expression(driver, false, true);
+
+ /* return the target */
+ return dvar;
+}
+
+/* This frees the driver itself */
+void fcurve_free_driver(FCurve *fcu)
+{
+ ChannelDriver *driver;
+ DriverVar *dvar, *dvarn;
+
+ /* sanity checks */
+ if (ELEM(NULL, fcu, fcu->driver)) {
+ return;
+ }
+ driver = fcu->driver;
+
+ /* free driver targets */
+ for (dvar = driver->variables.first; dvar; dvar = dvarn) {
+ dvarn = dvar->next;
+ driver_free_variable_ex(driver, dvar);
+ }
+
+#ifdef WITH_PYTHON
+ /* free compiled driver expression */
+ if (driver->expr_comp) {
+ BPY_DECREF(driver->expr_comp);
+ }
+#endif
+
+ BLI_expr_pylike_free(driver->expr_simple);
+
+ /* Free driver itself, then set F-Curve's point to this to NULL
+ * (as the curve may still be used). */
+ MEM_freeN(driver);
+ fcu->driver = NULL;
+}
+
+/* This makes a copy of the given driver */
+ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
+{
+ ChannelDriver *ndriver;
+
+ /* sanity checks */
+ if (driver == NULL) {
+ return NULL;
+ }
+
+ /* copy all data */
+ ndriver = MEM_dupallocN(driver);
+ ndriver->expr_comp = NULL;
+ ndriver->expr_simple = NULL;
+
+ /* copy variables */
+
+ /* to get rid of refs to non-copied data (that's still used on original) */
+ BLI_listbase_clear(&ndriver->variables);
+ driver_variables_copy(&ndriver->variables, &driver->variables);
+
+ /* return the new driver */
+ return ndriver;
+}
+
+/* Driver Expression Evaluation --------------- */
+
+/* Index constants for the expression parameter array. */
+enum {
+ /* Index of the 'frame' variable. */
+ VAR_INDEX_FRAME = 0,
+ /* Index of the first user-defined driver variable. */
+ VAR_INDEX_CUSTOM
+};
+
+static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver)
+{
+ /* Prepare parameter names. */
+ int names_len = BLI_listbase_count(&driver->variables);
+ const char **names = BLI_array_alloca(names, names_len + VAR_INDEX_CUSTOM);
+ int i = VAR_INDEX_CUSTOM;
+
+ names[VAR_INDEX_FRAME] = "frame";
+
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ names[i++] = dvar->name;
+ }
+
+ return BLI_expr_pylike_parse(driver->expression, names, names_len + VAR_INDEX_CUSTOM);
+}
+
+static bool driver_check_simple_expr_depends_on_time(ExprPyLike_Parsed *expr)
+{
+ /* Check if the 'frame' parameter is actually used. */
+ return BLI_expr_pylike_is_using_param(expr, VAR_INDEX_FRAME);
+}
+
+static bool driver_evaluate_simple_expr(ChannelDriver *driver,
+ ExprPyLike_Parsed *expr,
+ float *result,
+ float time)
+{
+ /* Prepare parameter values. */
+ int vars_len = BLI_listbase_count(&driver->variables);
+ double *vars = BLI_array_alloca(vars, vars_len + VAR_INDEX_CUSTOM);
+ int i = VAR_INDEX_CUSTOM;
+
+ vars[VAR_INDEX_FRAME] = time;
+
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ vars[i++] = driver_get_variable_value(driver, dvar);
+ }
+
+ /* Evaluate expression. */
+ double result_val;
+ eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(
+ expr, vars, vars_len + VAR_INDEX_CUSTOM, &result_val);
+ const char *message;
+
+ switch (status) {
+ case EXPR_PYLIKE_SUCCESS:
+ if (isfinite(result_val)) {
+ *result = (float)result_val;
+ }
+ return true;
+
+ case EXPR_PYLIKE_DIV_BY_ZERO:
+ case EXPR_PYLIKE_MATH_ERROR:
+ message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error";
+ CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression);
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ return true;
+
+ default:
+ /* arriving here means a bug, not user error */
+ CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression);
+ return false;
+ }
+}
+
+/* Compile and cache the driver expression if necessary, with thread safety. */
+static bool driver_compile_simple_expr(ChannelDriver *driver)
+{
+ if (driver->expr_simple != NULL) {
+ return true;
+ }
+
+ if (driver->type != DRIVER_TYPE_PYTHON) {
+ return false;
+ }
+
+ /* It's safe to parse in multiple threads; at worst it'll
+ * waste some effort, but in return avoids mutex contention. */
+ ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver);
+
+ /* Store the result if the field is still NULL, or discard
+ * it if another thread got here first. */
+ if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) {
+ BLI_expr_pylike_free(expr);
+ }
+
+ return true;
+}
+
+/* Try using the simple expression evaluator to compute the result of the driver.
+ * On success, stores the result and returns true; on failure result is set to 0. */
+static bool driver_try_evaluate_simple_expr(ChannelDriver *driver,
+ ChannelDriver *driver_orig,
+ float *result,
+ float time)
+{
+ *result = 0.0f;
+
+ return driver_compile_simple_expr(driver_orig) &&
+ BLI_expr_pylike_is_valid(driver_orig->expr_simple) &&
+ driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
+}
+
+/* Check if the expression in the driver conforms to the simple subset. */
+bool BKE_driver_has_simple_expression(ChannelDriver *driver)
+{
+ return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
+}
+
+/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive
+ * time dependencies nor special exceptions in the depsgraph evaluation. */
+static bool python_driver_exression_depends_on_time(const char *expression)
+{
+ if (expression[0] == '\0') {
+ /* Empty expression depends on nothing. */
+ return false;
+ }
+ if (strchr(expression, '(') != NULL) {
+ /* Function calls are considered dependent on a time. */
+ return true;
+ }
+ if (strstr(expression, "frame") != NULL) {
+ /* Variable `frame` depends on time. */
+ /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */
+ return true;
+ }
+ /* Possible indirect time relation s should be handled via variable targets. */
+ return false;
+}
+
+/* Check if the expression in the driver may depend on the current frame. */
+bool BKE_driver_expression_depends_on_time(ChannelDriver *driver)
+{
+ if (driver->type != DRIVER_TYPE_PYTHON) {
+ return false;
+ }
+
+ if (BKE_driver_has_simple_expression(driver)) {
+ /* Simple expressions can be checked exactly. */
+ return driver_check_simple_expr_depends_on_time(driver->expr_simple);
+ }
+ else {
+ /* Otherwise, heuristically scan the expression string for certain patterns. */
+ return python_driver_exression_depends_on_time(driver->expression);
+ }
+}
+
+/* Reset cached compiled expression data */
+void BKE_driver_invalidate_expression(ChannelDriver *driver,
+ bool expr_changed,
+ bool varname_changed)
+{
+ if (expr_changed || varname_changed) {
+ BLI_expr_pylike_free(driver->expr_simple);
+ driver->expr_simple = NULL;
+ }
+
+#ifdef WITH_PYTHON
+ if (expr_changed) {
+ driver->flag |= DRIVER_FLAG_RECOMPILE;
+ }
+
+ if (varname_changed) {
+ driver->flag |= DRIVER_FLAG_RENAMEVAR;
+ }
+#endif
+}
+
+/* Driver Evaluation -------------------------- */
+
+/* Evaluate a Driver Variable to get a value that contributes to the final */
+float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
+{
+ const DriverVarTypeInfo *dvti;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dvar)) {
+ return 0.0f;
+ }
+
+ /* call the relevant callbacks to get the variable value
+ * using the variable type info, storing the obtained value
+ * in dvar->curval so that drivers can be debugged
+ */
+ dvti = get_dvar_typeinfo(dvar->type);
+
+ if (dvti && dvti->get_value) {
+ dvar->curval = dvti->get_value(driver, dvar);
+ }
+ else {
+ dvar->curval = 0.0f;
+ }
+
+ return dvar->curval;
+}
+
+static void evaluate_driver_sum(ChannelDriver *driver)
+{
+ DriverVar *dvar;
+
+ /* check how many variables there are first (i.e. just one?) */
+ if (BLI_listbase_is_single(&driver->variables)) {
+ /* just one target, so just use that */
+ dvar = driver->variables.first;
+ driver->curval = driver_get_variable_value(driver, dvar);
+ return;
+ }
+
+ /* more than one target, so average the values of the targets */
+ float value = 0.0f;
+ int tot = 0;
+
+ /* loop through targets, adding (hopefully we don't get any overflow!) */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ value += driver_get_variable_value(driver, dvar);
+ tot++;
+ }
+
+ /* perform operations on the total if appropriate */
+ if (driver->type == DRIVER_TYPE_AVERAGE) {
+ driver->curval = tot ? (value / (float)tot) : 0.0f;
+ }
+ else {
+ driver->curval = value;
+ }
+}
+
+static void evaluate_driver_min_max(ChannelDriver *driver)
+{
+ DriverVar *dvar;
+ float value = 0.0f;
+
+ /* loop through the variables, getting the values and comparing them to existing ones */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* get value */
+ float tmp_val = driver_get_variable_value(driver, dvar);
+
+ /* store this value if appropriate */
+ if (dvar->prev) {
+ /* check if greater/smaller than the baseline */
+ if (driver->type == DRIVER_TYPE_MAX) {
+ /* max? */
+ if (tmp_val > value) {
+ value = tmp_val;
+ }
+ }
+ else {
+ /* min? */
+ if (tmp_val < value) {
+ value = tmp_val;
+ }
+ }
+ }
+ else {
+ /* first item - make this the baseline for comparisons */
+ value = tmp_val;
+ }
+ }
+
+ /* store value in driver */
+ driver->curval = value;
+}
+
+static void evaluate_driver_python(PathResolvedRNA *anim_rna,
+ ChannelDriver *driver,
+ ChannelDriver *driver_orig,
+ const float evaltime)
+{
+ /* check for empty or invalid expression */
+ if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) {
+ driver->curval = 0.0f;
+ }
+ else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) {
+#ifdef WITH_PYTHON
+ /* this evaluates the expression using Python, and returns its result:
+ * - on errors it reports, then returns 0.0f
+ */
+ BLI_mutex_lock(&python_driver_lock);
+
+ driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime);
+
+ BLI_mutex_unlock(&python_driver_lock);
+#else /* WITH_PYTHON*/
+ UNUSED_VARS(anim_rna, evaltime);
+#endif /* WITH_PYTHON*/
+ }
+}
+
+/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
+ * - "evaltime" is the frame at which F-Curve is being evaluated
+ * - has to return a float value
+ * - driver_orig is where we cache Python expressions, in case of COW
+ */
+float evaluate_driver(PathResolvedRNA *anim_rna,
+ ChannelDriver *driver,
+ ChannelDriver *driver_orig,
+ const float evaltime)
+{
+ /* check if driver can be evaluated */
+ if (driver_orig->flag & DRIVER_FLAG_INVALID) {
+ return 0.0f;
+ }
+
+ switch (driver->type) {
+ case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
+ case DRIVER_TYPE_SUM: /* sum values of driver targets */
+ evaluate_driver_sum(driver);
+ break;
+ case DRIVER_TYPE_MIN: /* smallest value */
+ case DRIVER_TYPE_MAX: /* largest value */
+ evaluate_driver_min_max(driver);
+ break;
+ case DRIVER_TYPE_PYTHON: /* expression */
+ evaluate_driver_python(anim_rna, driver, driver_orig, evaltime);
+ break;
+ default:
+ /* special 'hack' - just use stored value
+ * This is currently used as the mechanism which allows animated settings to be able
+ * to be changed via the UI.
+ */
+ break;
+ }
+
+ /* return value for driver */
+ return driver->curval;
+}
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 96efac8f2c5..5340fa63f38 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -81,6 +81,8 @@
# include "RE_shader_ext.h"
+# include "CLG_log.h"
+
# include "manta_fluid_API.h"
#endif /* WITH_FLUID */
@@ -96,6 +98,8 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need
#ifdef WITH_FLUID
// #define DEBUG_PRINT
+static CLG_LogRef LOG = {"bke.fluid"};
+
/* -------------------------------------------------------------------- */
/** \name Fluid API
* \{ */
@@ -487,32 +491,6 @@ static void manta_set_domain_from_mesh(FluidDomainSettings *mds,
mds->cell_size[2] /= (float)mds->base_res[2];
}
-static void manta_set_domain_gravity(Scene *scene, FluidDomainSettings *mds)
-{
- const float normalization_factor = 1.0f / 9.81f;
-
- /* Use global gravity if enabled. */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- float gravity[3];
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- /* Map default value to 1.0. */
- mul_v3_fl(gravity, normalization_factor);
-
- /* Convert gravity to domain space. */
- float gravity_mag = len_v3(gravity);
- mul_mat3_m4_v3(mds->imat, gravity);
- normalize_v3(gravity);
- mul_v3_fl(gravity, gravity_mag);
-
- copy_v3_v3(mds->gravity, gravity);
- }
- else {
- mul_v3_fl(mds->gravity, normalization_factor);
- }
-
- mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity);
-}
-
static bool BKE_fluid_modifier_init(
FluidModifierData *mmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me)
{
@@ -523,8 +501,11 @@ static bool BKE_fluid_modifier_init(
int res[3];
/* Set domain dimensions from mesh. */
manta_set_domain_from_mesh(mds, ob, me, true);
- /* Set domain gravity. */
- manta_set_domain_gravity(scene, mds);
+ /* Set domain gravity, use global gravity if enabled. */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(mds->gravity, scene->physics_settings.gravity);
+ }
+ mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity);
/* Reset domain values. */
zero_v3_int(mds->shift);
zero_v3(mds->shift_f);
@@ -948,11 +929,7 @@ static void sample_effector(FluidEffectorSettings *mes,
velocity_map[index * 3 + 2] += hit_vel[2];
# ifdef DEBUG_PRINT
/* Debugging: Print object velocities. */
- printf("adding effector object vel: [%f, %f, %f], dx is: %f\n",
- hit_vel[0],
- hit_vel[1],
- hit_vel[2],
- mds->dx);
+ printf("adding effector object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]);
# endif
}
}
@@ -1996,9 +1973,9 @@ static void sample_mesh(FluidFlowSettings *mfs,
normalize_v3(hit_normal);
/* Apply normal directional velocity. */
- velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal * 0.25f;
+ velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal;
+ velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal;
+ velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal;
}
/* Apply object velocity. */
if (has_velocity && mfs->vel_multi) {
@@ -3773,6 +3750,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
/* Fluid domain init must not fail in order to continue modifier evaluation. */
if (!mds->fluid && !BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me)) {
+ CLOG_ERROR(&LOG, "Fluid initialization failed. Should not happen!");
return;
}
BLI_assert(mds->fluid);
@@ -3794,6 +3772,12 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
/* Get distance between cache start and current frame for total time. */
mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length;
+ /* Ensure that gravity is copied over every frame (could be keyframed). */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(mds->gravity, scene->physics_settings.gravity);
+ mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity);
+ }
+
int next_frame = scene_framenr + 1;
int prev_frame = scene_framenr - 1;
/* Ensure positivity of previous frame. */
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c
index 5cdb7761540..9d66b509c72 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.c
@@ -247,12 +247,65 @@ Hair *BKE_hair_copy_for_eval(Hair *hair_src, bool reference)
return result;
}
-static Hair *hair_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph),
- struct Scene *UNUSED(scene),
- Object *UNUSED(object),
+static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
Hair *hair_input)
{
- return hair_input;
+ Hair *hair = hair_input;
+
+ /* Modifier evaluation modes. */
+ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
+ const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(object, &virtualModifierData);
+
+ /* Evaluate modifiers. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if ((mti->type == eModifierTypeType_OnlyDeform) &&
+ (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
+ /* Ensure we are not modifying the input. */
+ if (hair == hair_input) {
+ hair = BKE_hair_copy_for_eval(hair, true);
+ }
+
+ /* Ensure we are not overwriting referenced data. */
+ CustomData_duplicate_referenced_layer(&hair->pdata, CD_LOCATION, hair->totpoint);
+ BKE_hair_update_customdata_pointers(hair);
+
+ /* Created deformed coordinates array on demand. */
+ mti->deformVerts(md, &mectx, NULL, hair->co, hair->totpoint);
+ }
+ else if (mti->modifyHair) {
+ /* Ensure we are not modifying the input. */
+ if (hair == hair_input) {
+ hair = BKE_hair_copy_for_eval(hair, true);
+ }
+
+ Hair *hair_next = mti->modifyHair(md, &mectx, hair);
+
+ if (hair_next && hair_next != hair) {
+ /* If the modifier returned a new hair, release the old one. */
+ if (hair != hair_input) {
+ BKE_id_free(NULL, hair);
+ }
+ hair = hair_next;
+ }
+ }
+ }
+
+ return hair;
}
void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index 5a6e8f532c9..fafd223a0e5 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -92,6 +92,7 @@ static void id_type_init(void)
INIT_TYPE(ID_HA);
INIT_TYPE(ID_PT);
INIT_TYPE(ID_VO);
+ INIT_TYPE(ID_SIM);
/* Special naughty boy... */
BLI_assert(IDType_ID_LINK_PLACEHOLDER.main_listbase_index == INDEX_ID_NULL);
@@ -251,6 +252,7 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(PT);
CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
+ CASE_IDFILTER(SIM);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
CASE_IDFILTER(TE);
@@ -302,6 +304,7 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
CASE_IDFILTER(PT);
CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
+ CASE_IDFILTER(SIM);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
CASE_IDFILTER(TE);
@@ -356,6 +359,7 @@ int BKE_idtype_idcode_to_index(const short idcode)
CASE_IDINDEX(LP);
CASE_IDINDEX(SCE);
CASE_IDINDEX(SCR);
+ CASE_IDINDEX(SIM);
CASE_IDINDEX(SPK);
CASE_IDINDEX(SO);
CASE_IDINDEX(TE);
@@ -417,6 +421,7 @@ short BKE_idtype_idcode_from_index(const int index)
CASE_IDCODE(LP);
CASE_IDCODE(SCE);
CASE_IDCODE(SCR);
+ CASE_IDCODE(SIM);
CASE_IDCODE(SPK);
CASE_IDCODE(SO);
CASE_IDCODE(TE);
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index ee1bd5afa61..f5b28355d85 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -571,7 +571,7 @@ ImageTile *BKE_image_get_tile(Image *ima, int tile_number)
return NULL;
}
-ImageTile *BKE_image_get_tile_from_iuser(Image *ima, ImageUser *iuser)
+ImageTile *BKE_image_get_tile_from_iuser(Image *ima, const ImageUser *iuser)
{
return BKE_image_get_tile(ima, (iuser && iuser->tile) ? iuser->tile : 1001);
}
@@ -4796,7 +4796,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry,
return ibuf;
}
-BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
+BLI_INLINE bool image_quick_test(Image *ima, const ImageUser *iuser)
{
if (ima == NULL) {
return false;
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index b0b88a13a75..12c1cf6bafa 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -60,6 +60,7 @@
#include "BKE_action.h"
#include "BKE_anim_data.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_ipo.h"
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index d371af93bb7..68893ad8877 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -1134,7 +1134,7 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) {
+ if (!(mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
continue;
}
if (!(md->mode & eModifierMode_Realtime)) {
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index d1337620de8..fe25016344e 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -36,38 +36,12 @@
#include "MEM_guardedalloc.h"
/* all types are needed here, in order to do memory operations */
+#include "DNA_ID.h"
#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_cachefile_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_hair_types.h"
-#include "DNA_ipo_types.h"
#include "DNA_key_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_light_types.h"
-#include "DNA_lightprobe_types.h"
-#include "DNA_linestyle_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_pointcloud_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sound_types.h"
-#include "DNA_speaker_types.h"
-#include "DNA_text_types.h"
-#include "DNA_vfont_types.h"
-#include "DNA_volume_types.h"
-#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
-#include "DNA_world_types.h"
#include "BLI_utildefines.h"
@@ -80,50 +54,21 @@
#include "BLT_translation.h"
-#include "BKE_action.h"
#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_bpath.h"
-#include "BKE_brush.h"
-#include "BKE_cachefile.h"
-#include "BKE_camera.h"
-#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_curve.h"
-#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_hair.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
-#include "BKE_image.h"
#include "BKE_key.h"
-#include "BKE_lattice.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
-#include "BKE_light.h"
-#include "BKE_lightprobe.h"
-#include "BKE_linestyle.h"
#include "BKE_main.h"
-#include "BKE_mask.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_mesh.h"
-#include "BKE_movieclip.h"
#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-#include "BKE_pointcloud.h"
#include "BKE_rigidbody.h"
-#include "BKE_scene.h"
-#include "BKE_sound.h"
-#include "BKE_speaker.h"
-#include "BKE_text.h"
-#include "BKE_texture.h"
-#include "BKE_volume.h"
-#include "BKE_world.h"
#include "DEG_depsgraph.h"
@@ -663,7 +608,7 @@ static void id_swap(Main *bmain, ID *id_a, ID *id_b, const bool do_full_id)
* Does a mere memory swap over the whole IDs data (including type-specific memory).
* \note Most internal ID data itself is not swapped (only IDProperties are).
*
- * \param bmain May be NULL, in which case there will be no remapping of internal pointers to
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
* itself.
*/
void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b)
@@ -675,7 +620,7 @@ void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b)
* Does a mere memory swap over the whole IDs data (including type-specific memory).
* \note All internal ID data itself is also swapped.
*
- * \param bmain May be NULL, in which case there will be no remapping of internal pointers to
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
* itself.
*/
void BKE_lib_id_swap_full(Main *bmain, ID *id_a, ID *id_b)
@@ -1260,7 +1205,7 @@ ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *nam
*
* \note All other IDs beside given one are assumed already properly sorted in the list.
*
- * \param id_sorting_hint Ignored if NULL. Otherwise, used to check if we can insert \a id
+ * \param id_sorting_hint: Ignored if NULL. Otherwise, used to check if we can insert \a id
* immediately before or after that pointer. It must always be into given \a lb list.
*/
void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 245e4f43452..fdee5500fbd 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -23,80 +23,20 @@
#include "MEM_guardedalloc.h"
/* all types are needed here, in order to do memory operations */
-#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_cachefile_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_collection_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_ipo_types.h"
-#include "DNA_key_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_light_types.h"
-#include "DNA_lightprobe_types.h"
-#include "DNA_linestyle_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sound_types.h"
-#include "DNA_speaker_types.h"
-#include "DNA_text_types.h"
-#include "DNA_vfont_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
-#include "DNA_world_types.h"
+#include "DNA_ID.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BKE_action.h"
#include "BKE_anim_data.h"
-#include "BKE_armature.h"
-#include "BKE_brush.h"
-#include "BKE_cachefile.h"
-#include "BKE_camera.h"
-#include "BKE_collection.h"
-#include "BKE_curve.h"
-#include "BKE_font.h"
-#include "BKE_gpencil.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
-#include "BKE_image.h"
-#include "BKE_ipo.h"
-#include "BKE_key.h"
-#include "BKE_lattice.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_lib_remap.h"
#include "BKE_library.h"
-#include "BKE_light.h"
-#include "BKE_lightprobe.h"
-#include "BKE_linestyle.h"
#include "BKE_main.h"
-#include "BKE_mask.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_mesh.h"
-#include "BKE_movieclip.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
-#include "BKE_sound.h"
-#include "BKE_speaker.h"
-#include "BKE_text.h"
-#include "BKE_texture.h"
-#include "BKE_workspace.h"
-#include "BKE_world.h"
#include "lib_intern.h"
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 2ca03fd5d7e..31ac8ca623b 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -49,6 +49,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
@@ -67,7 +68,7 @@
#include "BKE_anim_data.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
@@ -182,6 +183,41 @@ static void library_foreach_idpropertiesForeachIDLink(IDProperty *id_prop, void
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock)
+{
+ IDP_foreach_property(
+ sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
+
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, (ID **)&default_value->value, IDWALK_CB_USER);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, (ID **)&default_value->value, IDWALK_CB_USER);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw),
ID **id_pointer,
void *user_data,
@@ -499,14 +535,12 @@ static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *are
FOREACH_FINALIZE_VOID;
}
-static void library_foreach_ID_as_subdata_link(ID **id_pp,
- LibraryIDLinkCallback callback,
- void *user_data,
- int flag,
- LibraryForeachIDData *data)
+static void library_foreach_ID_as_subdata_link(ID **id_pp, LibraryForeachIDData *data)
{
/* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */
ID *id = *id_pp;
+ const int flag = data->flag;
+
FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_EMBEDDED);
BLI_assert(id == *id_pp);
@@ -523,7 +557,8 @@ static void library_foreach_ID_as_subdata_link(ID **id_pp,
}
}
else {
- library_foreach_ID_link(data->bmain, data->owner_id, id, callback, user_data, flag, data);
+ library_foreach_ID_link(
+ data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data);
}
FOREACH_FINALIZE_VOID;
@@ -639,8 +674,7 @@ static void library_foreach_ID_link(Main *bmain,
CALLBACK_INVOKE(scene->r.bake.cage_object, IDWALK_CB_NOP);
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, &data);
}
if (scene->ed) {
Sequence *seq;
@@ -893,8 +927,7 @@ static void library_foreach_ID_link(Main *bmain,
Material *material = (Material *)id;
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, &data);
}
if (material->texpaintslot != NULL) {
CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
@@ -910,8 +943,7 @@ static void library_foreach_ID_link(Main *bmain,
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, &data);
}
CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
break;
@@ -927,8 +959,7 @@ static void library_foreach_ID_link(Main *bmain,
Light *lamp = (Light *)id;
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, &data);
}
break;
}
@@ -958,8 +989,7 @@ static void library_foreach_ID_link(Main *bmain,
World *world = (World *)id;
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, &data);
}
break;
}
@@ -994,22 +1024,18 @@ static void library_foreach_ID_link(Main *bmain,
IDP_foreach_property(
node->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- IDP_foreach_property(
- sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
+ library_foreach_node_socket(&data, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
- IDP_foreach_property(
- sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
+ library_foreach_node_socket(&data, sock);
}
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
- IDP_foreach_property(
- sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
+ library_foreach_node_socket(&data, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
- IDP_foreach_property(
- sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
+ library_foreach_node_socket(&data, sock);
}
break;
}
@@ -1119,8 +1145,7 @@ static void library_foreach_ID_link(Main *bmain,
}
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, &data);
}
LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) {
@@ -1246,6 +1271,14 @@ static void library_foreach_ID_link(Main *bmain,
}
break;
}
+ case ID_SIM: {
+ Simulation *simulation = (Simulation *)id;
+ if (simulation->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link((ID **)&simulation->nodetree, &data);
+ }
+ break;
+ }
/* Nothing needed for those... */
case ID_IM:
@@ -1300,14 +1333,11 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
}
/**
- * Say whether given \a id_type_owner can use (in any way) a data-block of \a id_type_used.
+ * Say whether given \a id_owner may use (in any way) a data-block of \a id_type_used.
*
* This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above,
- * quite useful to reduce* useless iterations in some cases.
+ * quite useful to reduce useless iterations in some cases.
*/
-/* XXX This has to be fully rethink, basing check on ID type is not really working anymore
- * (and even worth once IDProps will support ID pointers),
- * we'll have to do some quick checks on IDs themselves... */
bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
{
/* any type of ID can be used in custom props. */
@@ -1417,6 +1447,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_PAL:
case ID_PC:
case ID_CF:
+ case ID_SIM:
/* Those types never use/reference other IDs... */
return false;
case ID_IP:
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index 3d0503b2e70..13f4815124b 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -97,7 +97,7 @@ static void light_free_data(ID *id)
/* is no lib link block, but light extension */
if (la->nodetree) {
- ntreeFreeNestedTree(la->nodetree);
+ ntreeFreeEmbeddedTree(la->nodetree);
MEM_freeN(la->nodetree);
la->nodetree = NULL;
}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 42506e0d7c8..0401ae48b5c 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -125,7 +125,7 @@ static void linestyle_free_data(ID *id)
/* is no lib link block, but linestyle extension */
if (linestyle->nodetree) {
- ntreeFreeNestedTree(linestyle->nodetree);
+ ntreeFreeEmbeddedTree(linestyle->nodetree);
MEM_freeN(linestyle->nodetree);
linestyle->nodetree = NULL;
}
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index caa29f7817a..ea3bee8b2f6 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -479,6 +479,8 @@ ListBase *which_libbase(Main *bmain, short type)
return &(bmain->pointclouds);
case ID_VO:
return &(bmain->volumes);
+ case ID_SIM:
+ return &(bmain->simulations);
}
return NULL;
}
@@ -554,6 +556,7 @@ int set_listbasepointers(Main *bmain, ListBase **lb)
lb[INDEX_ID_WS] = &(bmain->workspaces); /* before wm, so it's freed after it! */
lb[INDEX_ID_WM] = &(bmain->wm);
lb[INDEX_ID_MSK] = &(bmain->masks);
+ lb[INDEX_ID_SIM] = &(bmain->simulations);
lb[INDEX_ID_NULL] = NULL;
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 1b21ff9b36e..440f46f4f7c 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -130,7 +130,7 @@ static void material_free_data(ID *id)
/* is no lib link block, but material extension */
if (material->nodetree) {
- ntreeFreeNestedTree(material->nodetree);
+ ntreeFreeEmbeddedTree(material->nodetree);
MEM_freeN(material->nodetree);
material->nodetree = NULL;
}
@@ -1601,7 +1601,7 @@ void BKE_material_copybuf_paste(Main *bmain, Material *ma)
GPU_material_free(&ma->gpumaterial);
if (ma->nodetree) {
- ntreeFreeNestedTree(ma->nodetree);
+ ntreeFreeEmbeddedTree(ma->nodetree);
MEM_freeN(ma->nodetree);
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index 28a32e1573b..e7dbd7be664 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -1353,7 +1353,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
add_shapekey_layers(mesh_temp, me);
}
- result = mti->applyModifier(md_eval, &mectx, mesh_temp);
+ result = mti->modifyMesh(md_eval, &mectx, mesh_temp);
ASSERT_IS_VALID_MESH(result);
if (mesh_temp != result) {
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index e5be85b5ec7..f0d19f01aab 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -1300,9 +1300,9 @@ static void loop_split_worker_do(LoopSplitTaskDataCommon *common_data,
}
}
-static void loop_split_worker(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid))
+static void loop_split_worker(TaskPool *__restrict pool, void *taskdata)
{
- LoopSplitTaskDataCommon *common_data = BLI_task_pool_userdata(pool);
+ LoopSplitTaskDataCommon *common_data = BLI_task_pool_user_data(pool);
LoopSplitTaskData *data = taskdata;
/* Temp edge vectors stack, only used when computing lnor spacearr. */
@@ -1704,11 +1704,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
loop_split_generator(NULL, &common_data);
}
else {
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
-
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &common_data, TASK_PRIORITY_HIGH);
+ TaskPool *task_pool = BLI_task_pool_create(&common_data, TASK_PRIORITY_HIGH);
loop_split_generator(task_pool, &common_data);
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index a2a198cdb0d..d6f945cf34f 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -452,9 +452,7 @@ finally:
pRes[3] = fSign;
}
-static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
struct SGLSLMeshToTangent *mesh2tangent = taskdata;
/* new computation method */
@@ -658,9 +656,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
/* Calculation */
if (looptri_len != 0) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL, TASK_PRIORITY_LOW);
+ TaskPool *task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW);
tangent_mask_curr = 0;
/* Calculate tangent layers */
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 0a76b61cdb1..4b05f4635a2 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -945,11 +945,9 @@ void modifier_path_init(char *path, int path_maxlen, const char *name)
BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name);
}
-/* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */
+/* wrapper around ModifierTypeInfo.modifyMesh that ensures valid normals */
-struct Mesh *modwrap_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- struct Mesh *me)
+struct Mesh *modwrap_modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct Mesh *me)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
@@ -957,7 +955,7 @@ struct Mesh *modwrap_applyModifier(ModifierData *md,
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
BKE_mesh_calc_normals(me);
}
- return mti->applyModifier(md, ctx, me);
+ return mti->modifyMesh(md, ctx, me);
}
void modwrap_deformVerts(ModifierData *md,
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 193fe859def..4c7b791f103 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -460,6 +460,7 @@ typedef struct MovieClipCache {
float principal[2];
float polynomial_k[3];
float division_k[2];
+ float nuke_k[2];
short distortion_model;
bool undistortion_used;
@@ -908,6 +909,9 @@ static bool check_undistortion_cache_flags(const MovieClip *clip)
if (!equals_v2v2(&camera->division_k1, cache->postprocessed.division_k)) {
return false;
}
+ if (!equals_v2v2(&camera->nuke_k1, cache->postprocessed.nuke_k)) {
+ return false;
+ }
return true;
}
@@ -1010,6 +1014,7 @@ static void put_postprocessed_frame_to_cache(
copy_v2_v2(cache->postprocessed.principal, camera->principal);
copy_v3_v3(cache->postprocessed.polynomial_k, &camera->k1);
copy_v2_v2(cache->postprocessed.division_k, &camera->division_k1);
+ copy_v2_v2(cache->postprocessed.nuke_k, &camera->nuke_k1);
cache->postprocessed.undistortion_used = true;
}
else {
@@ -1512,7 +1517,8 @@ void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClip
undist_marker.pos[0] *= width;
undist_marker.pos[1] *= height * aspy;
- BKE_tracking_undistort_v2(&clip->tracking, undist_marker.pos, undist_marker.pos);
+ BKE_tracking_undistort_v2(
+ &clip->tracking, width, height, undist_marker.pos, undist_marker.pos);
undist_marker.pos[0] /= width;
undist_marker.pos[1] /= height * aspy;
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 69cd338e15f..d79dbbb7d32 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -290,7 +290,7 @@ Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph,
};
const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type);
- Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh);
+ Mesh *result = mti->modifyMesh(&mmd->modifier, &modifier_ctx, deformed_mesh);
if (result == deformed_mesh) {
result = BKE_mesh_copy_for_eval(deformed_mesh, true);
@@ -407,7 +407,7 @@ int multires_get_level(const Scene *scene,
mmd->renderlvl;
}
else if (ob->mode == OB_MODE_SCULPT) {
- return BKE_multires_sculpt_level_get(mmd);
+ return mmd->sculptlvl;
}
else if (ignore_simplify) {
return mmd->lvl;
@@ -2234,7 +2234,14 @@ void multiresModifier_sync_levels_ex(Object *ob_dst,
}
if (mmd_src->totlvl > mmd_dst->totlvl) {
- multiresModifier_subdivide_to_level(ob_dst, mmd_dst, mmd_src->totlvl);
+ if (mmd_dst->simple) {
+ multiresModifier_subdivide_to_level(
+ ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_SIMPLE);
+ }
+ else {
+ multiresModifier_subdivide_to_level(
+ ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_CATMULL_CLARK);
+ }
}
else {
multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
@@ -2516,12 +2523,3 @@ int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert),
return S;
}
-
-/* This is a workaround for T58473.
- * Force sculpting on the highest level for until the root of the issue is solved.
- *
- * When that issue is solved simple replace call of this function with mmd->sculptlvl. */
-int BKE_multires_sculpt_level_get(const struct MultiresModifierData *mmd)
-{
- return mmd->totlvl;
-}
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
index 02cd5f094a6..480a1d0b2a0 100644
--- a/source/blender/blenkernel/intern/multires_reshape.c
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -28,8 +28,6 @@
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
-#include "BLI_math_vector.h"
-
#include "BKE_customdata.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
@@ -37,14 +35,16 @@
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_subdiv.h"
+#include "BKE_subsurf.h"
+#include "BLI_math_vector.h"
#include "DEG_depsgraph_query.h"
#include "multires_reshape.h"
-/* ================================================================================================
- * Reshape from object.
- */
+/* -------------------------------------------------------------------- */
+/** \name Reshape from object
+ * \{ */
bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph,
struct Object *object,
@@ -93,9 +93,11 @@ bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph,
return result;
}
-/* ================================================================================================
- * Reshape from modifier.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reshape from modifier
+ * \{ */
bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph,
struct Object *object,
@@ -133,9 +135,11 @@ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph,
return result;
}
-/* ================================================================================================
- * Reshape from grids.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reshape from grids
+ * \{ */
bool multiresModifier_reshapeFromCCG(const int tot_level,
Mesh *coarse_mesh,
@@ -161,19 +165,24 @@ bool multiresModifier_reshapeFromCCG(const int tot_level,
return true;
}
-/* ================================================================================================
- * Subdivision.
- */
+/** \} */
-void multiresModifier_subdivide(Object *object, MultiresModifierData *mmd)
+/* -------------------------------------------------------------------- */
+/** \name Subdivision
+ * \{ */
+
+void multiresModifier_subdivide(Object *object,
+ MultiresModifierData *mmd,
+ const eMultiresSubdivideModeType mode)
{
const int top_level = mmd->totlvl + 1;
- multiresModifier_subdivide_to_level(object, mmd, top_level);
+ multiresModifier_subdivide_to_level(object, mmd, top_level, mode);
}
void multiresModifier_subdivide_to_level(struct Object *object,
struct MultiresModifierData *mmd,
- const int top_level)
+ const int top_level,
+ const eMultiresSubdivideModeType mode)
{
if (top_level <= mmd->totlvl) {
return;
@@ -190,7 +199,12 @@ void multiresModifier_subdivide_to_level(struct Object *object,
}
if (!has_mdisps || top_level == 1) {
multires_reshape_ensure_grids(coarse_mesh, top_level);
- multires_set_tot_level(object, mmd, top_level);
+ if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) {
+ multires_subdivide_create_tangent_displacement_linear_grids(object, mmd);
+ }
+ else {
+ multires_set_tot_level(object, mmd, top_level);
+ }
return;
}
@@ -199,25 +213,33 @@ void multiresModifier_subdivide_to_level(struct Object *object,
if (!multires_reshape_context_create_from_subdivide(&reshape_context, object, mmd, top_level)) {
return;
}
+
multires_reshape_store_original_grids(&reshape_context);
multires_reshape_ensure_grids(coarse_mesh, reshape_context.top.level);
multires_reshape_assign_final_coords_from_orig_mdisps(&reshape_context);
- /* Free original grids which makes it so smoothing with details thinks all the details were
- * added against base mesh's limit surface. This is similar behavior to as if we've done all
- * displacement in sculpt mode at the old top level and then propagated to the new top level. */
- multires_reshape_free_original_grids(&reshape_context);
+ if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) {
+ multires_reshape_smooth_object_grids(&reshape_context, mode);
+ }
+ else {
+ /* Free original grids which makes it so smoothing with details thinks all the details were
+ * added against base mesh's limit surface. This is similar behavior to as if we've done all
+ * displacement in sculpt mode at the old top level and then propagated to the new top level.*/
+ multires_reshape_free_original_grids(&reshape_context);
- multires_reshape_smooth_object_grids_with_details(&reshape_context);
+ multires_reshape_smooth_object_grids_with_details(&reshape_context);
+ }
multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
multires_reshape_context_free(&reshape_context);
multires_set_tot_level(object, mmd, top_level);
}
-/* ================================================================================================
- * Apply base.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Apply base
+ * \{ */
void multiresModifier_base_apply(struct Depsgraph *depsgraph,
Object *object,
@@ -263,3 +285,5 @@ void multiresModifier_base_apply(struct Depsgraph *depsgraph,
multires_reshape_context_free(&reshape_context);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h
index adfa2659661..644404b5cb3 100644
--- a/source/blender/blenkernel/intern/multires_reshape.h
+++ b/source/blender/blenkernel/intern/multires_reshape.h
@@ -26,6 +26,8 @@
#include "BLI_sys_types.h"
+#include "BKE_multires.h"
+
struct Depsgraph;
struct GridPaintMask;
struct MDisps;
@@ -138,7 +140,7 @@ typedef struct ReshapeConstGridElement {
float mask;
} ReshapeConstGridElement;
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Construct/destruct reshape context.
*/
@@ -156,6 +158,11 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
struct Object *object,
struct MultiresModifierData *mmd);
+bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context,
+ struct Depsgraph *depsgraph,
+ struct Object *object,
+ struct MultiresModifierData *mmd);
+
bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_context,
struct SubdivCCG *subdiv_ccg,
struct Mesh *base_mesh,
@@ -169,7 +176,7 @@ bool multires_reshape_context_create_from_subdivide(MultiresReshapeContext *resh
void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_context);
void multires_reshape_context_free(MultiresReshapeContext *reshape_context);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Helper accessors.
*/
@@ -214,7 +221,7 @@ ReshapeGridElement multires_reshape_grid_element_for_ptex_coord(
ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Sample limit surface of the base mesh.
*/
@@ -225,14 +232,14 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha
float r_P[3],
float r_tangent_matrix[3][3]);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Custom data preparation.
*/
/* Make sure custom data is allocated for the given level. */
void multires_reshape_ensure_grids(struct Mesh *mesh, const int level);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Functions specific to reshaping from a set of vertices in a object position.
*/
@@ -245,7 +252,7 @@ bool multires_reshape_assign_final_coords_from_vertcos(
const float (*vert_coords)[3],
const int num_vert_coords);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Functions specific to reshaping from CCG.
*/
@@ -255,7 +262,7 @@ bool multires_reshape_assign_final_coords_from_vertcos(
bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context,
struct SubdivCCG *subdiv_ccg);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Functions specific to reshaping from MDISPS.
*/
@@ -267,7 +274,7 @@ void multires_reshape_assign_final_coords_from_mdisps(
void multires_reshape_assign_final_coords_from_orig_mdisps(
const MultiresReshapeContext *reshape_context);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Displacement smooth.
*/
@@ -284,9 +291,10 @@ void multires_reshape_smooth_object_grids_with_details(
*
* Makes it so surface on top level looks smooth. Details are not preserved
*/
-void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context);
+void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context,
+ const enum eMultiresSubdivideModeType mode);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Displacement, space conversion.
*/
@@ -297,7 +305,7 @@ void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_conte
void multires_reshape_object_grids_to_tangent_displacement(
const MultiresReshapeContext *reshape_context);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Apply base.
*/
@@ -319,5 +327,4 @@ void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshap
*
* NOTE: Will re-evaluate all leading modifiers, so it's not cheap. */
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context);
-
#endif /* __BKE_INTERN_MULTIRES_RESHAPE_H__ */
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index 514608a0f1d..04acb95909f 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -48,6 +48,10 @@
#include "atomic_ops.h"
#include "subdiv_converter.h"
+/* -------------------------------------------------------------------- */
+/** \name Local Structs
+ * \{ */
+
typedef struct SurfacePoint {
float P[3];
float tangent_matrix[3][3];
@@ -115,11 +119,21 @@ typedef struct MultiresReshapeSmoothContext {
Subdiv *reshape_subdiv;
SurfaceGrid *base_surface_grids;
+
+ /* Defines how displacement is interpolated on the higher levels (for example, whether
+ * displacement is smoothed in Catmull-Clark mode or interpolated linearly preserving sharp edges
+ * of the current sculpt level).
+ *
+ * NOTE: Uses same enumerator type as Subdivide operator, since the values are the same and
+ * decoupling type just adds extra headache to convert one enumerator to another. */
+ eMultiresSubdivideModeType smoothing_type;
} MultiresReshapeSmoothContext;
-/* ================================================================================================
- * Masks.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Masks
+ * \{ */
/* Interpolate mask grid at a reshape level.
* Will return 0 if there is no masks custom data layer. */
@@ -165,9 +179,11 @@ static float interpolate_masks_grid(const MultiresReshapeSmoothContext *reshape_
mask_elements[2] * weights[2] + mask_elements[3] * weights[3];
}
-/* ================================================================================================
- * Surface.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Surface
+ * \{ */
static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_smooth_context)
{
@@ -227,9 +243,11 @@ static void base_surface_grids_write(const MultiresReshapeSmoothContext *reshape
copy_m3_m3(point->tangent_matrix, tangent_matrix);
}
-/* ================================================================================================
- * Evaluation of subdivision surface at a reshape level.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation of subdivision surface at a reshape level
+ * \{ */
typedef void (*ForeachTopLevelGridCoordCallback)(
const MultiresReshapeSmoothContext *reshape_smooth_context,
@@ -383,11 +401,14 @@ static void foreach_toplevel_grid_coord(const MultiresReshapeSmoothContext *resh
0, num_faces, &data, foreach_toplevel_grid_coord_task, &parallel_range_settings);
}
-/* ================================================================================================
- * Generation of a topology information for OpenSubdiv converter.
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generation of a topology information for OpenSubdiv converter
*
* Calculates vertices, their coordinates in the original grids, and connections of them so then
- * it's easy to create OpenSubdiv's topology refiner. */
+ * it's easy to create OpenSubdiv's topology refiner.
+ * \{ */
static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_context)
{
@@ -399,15 +420,17 @@ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_co
static char get_effective_edge_crease_char(
const MultiresReshapeSmoothContext *reshape_smooth_context, const MEdge *base_edge)
{
- const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
- if (reshape_context->subdiv->settings.is_simple) {
+ if (ELEM(reshape_smooth_context->smoothing_type,
+ MULTIRES_SUBDIVIDE_LINEAR,
+ MULTIRES_SUBDIVIDE_SIMPLE)) {
return 255;
}
return base_edge->crease;
}
static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
- const MultiresReshapeContext *reshape_context)
+ const MultiresReshapeContext *reshape_context,
+ const eMultiresSubdivideModeType mode)
{
reshape_smooth_context->reshape_context = reshape_context;
@@ -427,6 +450,8 @@ static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
reshape_smooth_context->non_loose_base_edge_map = NULL;
reshape_smooth_context->reshape_subdiv = NULL;
reshape_smooth_context->base_surface_grids = NULL;
+
+ reshape_smooth_context->smoothing_type = mode;
}
static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_context)
@@ -461,12 +486,14 @@ static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context)
static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
const int num_vertices,
- const int UNUSED(num_edges),
+ const int num_edges,
const int num_loops,
const int num_polygons)
{
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
- const int max_edges = reshape_smooth_context->geometry.max_edges;
+ const int max_edges = reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR ?
+ num_edges :
+ reshape_smooth_context->geometry.max_edges;
/* NOTE: Calloc so the counters are re-set to 0 "for free". */
reshape_smooth_context->geometry.num_vertices = num_vertices;
@@ -659,6 +686,22 @@ static void foreach_vertex_of_loose_edge(const struct SubdivForeachContext *fore
}
}
+static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context,
+ const int subdiv_v1,
+ const int subdiv_v2,
+ const char crease)
+{
+ /* This is a bit overhead to use atomics in such a simple function called from many threads,
+ * but this allows to save quite measurable amount of memory. */
+ const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1);
+ BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges);
+
+ Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
+ edge->v1 = subdiv_v1;
+ edge->v2 = subdiv_v2;
+ edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease);
+}
+
static void foreach_edge(const struct SubdivForeachContext *foreach_context,
void *UNUSED(tls),
const int coarse_edge_index,
@@ -669,8 +712,15 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
- /* Ignore all inner face edges as they have sharpness of zero. */
- if (coarse_edge_index == ORIGINDEX_NONE) {
+ if (reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR) {
+ store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, (char)255);
+ return;
+ }
+
+ /* Ignore all inner face edges as they have sharpness of zero when using Catmull-Clark mode. In
+ * simple mode, all edges have maximum sharpness, so they can't be skipped. */
+ if (coarse_edge_index == ORIGINDEX_NONE &&
+ reshape_smooth_context->smoothing_type != MULTIRES_SUBDIVIDE_SIMPLE) {
return;
}
/* Ignore all loose edges as well, as they are not communicated to the OpenSubdiv. */
@@ -684,16 +734,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
if (crease == 0) {
return;
}
-
- /* This is a bit overhead to use atomics in such a simple function called from many threads,
- * but this allows to save quite measurable amount of memory. */
- const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1);
- BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges);
-
- Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
- edge->v1 = subdiv_v1;
- edge->v2 = subdiv_v2;
- edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease);
+ store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, crease);
}
static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshape_smooth_context)
@@ -757,9 +798,11 @@ static void geometry_create(MultiresReshapeSmoothContext *reshape_smooth_context
reshape_context->subdiv, &foreach_context, &mesh_settings, reshape_context->base_mesh);
}
-/* ================================================================================================
- * Generation of OpenSubdiv evaluator for topology created form reshape level.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generation of OpenSubdiv evaluator for topology created form reshape level
+ * \{ */
static OpenSubdiv_SchemeType get_scheme_type(const OpenSubdiv_Converter *UNUSED(converter))
{
@@ -1037,9 +1080,11 @@ static void reshape_subdiv_evaluate_limit_at_grid(
BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, corner);
}
-/* ================================================================================================
- * Evaluation of base surface.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation of base surface
+ * \{ */
static void evaluate_base_surface_grids_callback(
const MultiresReshapeSmoothContext *reshape_smooth_context,
@@ -1060,9 +1105,11 @@ static void evaluate_base_surface_grids(const MultiresReshapeSmoothContext *resh
foreach_toplevel_grid_coord(reshape_smooth_context, evaluate_base_surface_grids_callback, NULL);
}
-/* ================================================================================================
- * Evaluation of new surface.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation of new surface
+ * \{ */
/* Evaluate final position of the original (pre-sculpt-edit) point position at a given grid
* coordinate. */
@@ -1176,9 +1223,12 @@ static void evaluate_higher_grid_positions(
foreach_toplevel_grid_coord(
reshape_smooth_context, evaluate_higher_grid_positions_callback, NULL);
}
-/* ================================================================================================
- * Entry point.
- */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Entry point
+ * \{ */
void multires_reshape_smooth_object_grids_with_details(
const MultiresReshapeContext *reshape_context)
@@ -1190,7 +1240,12 @@ void multires_reshape_smooth_object_grids_with_details(
}
MultiresReshapeSmoothContext reshape_smooth_context;
- context_init(&reshape_smooth_context, reshape_context);
+ if (reshape_context->subdiv->settings.is_simple) {
+ context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_SIMPLE);
+ }
+ else {
+ context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_CATMULL_CLARK);
+ }
geometry_create(&reshape_smooth_context);
@@ -1206,7 +1261,8 @@ void multires_reshape_smooth_object_grids_with_details(
context_free(&reshape_smooth_context);
}
-void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context)
+void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context,
+ const eMultiresSubdivideModeType mode)
{
const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
if (level_difference == 0) {
@@ -1215,7 +1271,7 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_
}
MultiresReshapeSmoothContext reshape_smooth_context;
- context_init(&reshape_smooth_context, reshape_context);
+ context_init(&reshape_smooth_context, reshape_context, mode);
geometry_create(&reshape_smooth_context);
@@ -1226,3 +1282,5 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_
context_free(&reshape_smooth_context);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/multires_reshape_subdivide.c b/source/blender/blenkernel/intern/multires_reshape_subdivide.c
new file mode 100644
index 00000000000..5923e0430f2
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_reshape_subdivide.c
@@ -0,0 +1,106 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_subdiv.h"
+#include "BKE_subsurf.h"
+#include "BLI_math_vector.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "multires_reshape.h"
+
+static void multires_subdivide_create_object_space_linear_grids(Mesh *mesh)
+{
+ MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ const int totpoly = mesh->totpoly;
+ for (int p = 0; p < totpoly; p++) {
+ MPoly *poly = &mesh->mpoly[p];
+ float poly_center[3];
+ BKE_mesh_calc_poly_center(poly, &mesh->mloop[poly->loopstart], mesh->mvert, poly_center);
+ for (int l = 0; l < poly->totloop; l++) {
+ const int loop_index = poly->loopstart + l;
+
+ float(*disps)[3] = mdisps[loop_index].disps;
+ mdisps[loop_index].totdisp = 4;
+ mdisps[loop_index].level = 1;
+
+ int prev_loop_index = l - 1 >= 0 ? loop_index - 1 : loop_index + poly->totloop - 1;
+ int next_loop_index = l + 1 < poly->totloop ? loop_index + 1 : poly->loopstart;
+
+ MLoop *loop = &mesh->mloop[loop_index];
+ MLoop *loop_next = &mesh->mloop[next_loop_index];
+ MLoop *loop_prev = &mesh->mloop[prev_loop_index];
+
+ copy_v3_v3(disps[0], poly_center);
+ mid_v3_v3v3(disps[1], mesh->mvert[loop->v].co, mesh->mvert[loop_next->v].co);
+ mid_v3_v3v3(disps[2], mesh->mvert[loop->v].co, mesh->mvert[loop_prev->v].co);
+ copy_v3_v3(disps[3], mesh->mvert[loop->v].co);
+ }
+ }
+}
+
+void multires_subdivide_create_tangent_displacement_linear_grids(Object *object,
+ MultiresModifierData *mmd)
+{
+ Mesh *coarse_mesh = object->data;
+ multires_force_sculpt_rebuild(object);
+
+ MultiresReshapeContext reshape_context;
+
+ const int new_top_level = mmd->totlvl + 1;
+
+ const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS);
+ if (!has_mdisps) {
+ CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop);
+ }
+
+ if (new_top_level == 1) {
+ /* No MDISPS. Create new grids for level 1 using the edges mid point and poly centers. */
+ multires_reshape_ensure_grids(coarse_mesh, 1);
+ multires_subdivide_create_object_space_linear_grids(coarse_mesh);
+ }
+
+ /* Convert the new grids to tangent displacement. */
+ multires_set_tot_level(object, mmd, new_top_level);
+
+ if (!multires_reshape_context_create_from_subdivide(
+ &reshape_context, object, mmd, new_top_level)) {
+ return;
+ }
+
+ multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
+ multires_reshape_context_free(&reshape_context);
+}
diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c
index 57d790d2c34..4d54b7b6e87 100644
--- a/source/blender/blenkernel/intern/multires_reshape_util.c
+++ b/source/blender/blenkernel/intern/multires_reshape_util.c
@@ -43,9 +43,9 @@
#include "DEG_depsgraph_query.h"
-/* ================================================================================================
- * Construct/destruct reshape context.
- */
+/* -------------------------------------------------------------------- */
+/** \name Construct/destruct reshape context
+ * \{ */
/* Create subdivision surface descriptor which is configured for surface evaluation at a given
* multires modifier. */
@@ -152,6 +152,39 @@ static bool context_verify_or_free(MultiresReshapeContext *reshape_context)
return is_valid;
}
+bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context,
+ Depsgraph *depsgraph,
+ Object *object,
+ MultiresModifierData *mmd)
+{
+ context_zero(reshape_context);
+
+ const bool use_render_params = false;
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Mesh *base_mesh = (Mesh *)object->data;
+
+ reshape_context->depsgraph = depsgraph;
+ reshape_context->object = object;
+ reshape_context->mmd = mmd;
+
+ reshape_context->base_mesh = base_mesh;
+
+ reshape_context->subdiv = multires_reshape_create_subdiv(NULL, object, mmd);
+ reshape_context->need_free_subdiv = true;
+
+ reshape_context->reshape.level = multires_get_level(
+ scene_eval, object, mmd, use_render_params, true);
+ reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level(
+ reshape_context->reshape.level);
+
+ reshape_context->top.level = mmd->totlvl;
+ reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
+
+ context_init_commoon(reshape_context);
+
+ return context_verify_or_free(reshape_context);
+}
+
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context,
Depsgraph *depsgraph,
Object *object,
@@ -272,14 +305,16 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
multires_reshape_free_original_grids(reshape_context);
- MEM_freeN(reshape_context->face_start_grid_index);
- MEM_freeN(reshape_context->ptex_start_grid_index);
- MEM_freeN(reshape_context->grid_to_face_index);
+ MEM_SAFE_FREE(reshape_context->face_start_grid_index);
+ MEM_SAFE_FREE(reshape_context->ptex_start_grid_index);
+ MEM_SAFE_FREE(reshape_context->grid_to_face_index);
}
-/* ================================================================================================
- * Helper accessors.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Helper accessors
+ * \{ */
/* For the given grid index get index of face it was created for. */
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context,
@@ -453,9 +488,11 @@ ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
return grid_element;
}
-/* ================================================================================================
- * Sample limit surface of the base mesh.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample limit surface of the base mesh
+ * \{ */
void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord,
@@ -475,9 +512,11 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha
reshape_context, face_index, corner, dPdu, dPdv, r_tangent_matrix);
}
-/* ================================================================================================
- * Custom data preparation.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom data preparation
+ * \{ */
static void allocate_displacement_grid(MDisps *displacement_grid, const int level)
{
@@ -539,9 +578,11 @@ void multires_reshape_ensure_grids(Mesh *mesh, const int level)
ensure_mask_grids(mesh, level);
}
-/* ================================================================================================
- * Displacement, space conversion.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Displacement, space conversion
+ * \{ */
void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context)
{
@@ -678,10 +719,13 @@ void multires_reshape_object_grids_to_tangent_displacement(
NULL);
}
-/* ================================================================================================
- * MDISPS
- *
- * TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name MDISPS
+ * \{ */
+
+/* TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to
* own file. */
static void assign_final_coords_from_mdisps(const MultiresReshapeContext *reshape_context,
@@ -732,3 +776,5 @@ void multires_reshape_assign_final_coords_from_orig_mdisps(
foreach_grid_coordinate(
reshape_context, reshape_context->top.level, assign_final_coords_from_orig_mdisps, NULL);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c
new file mode 100644
index 00000000000..49de88db521
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.c
@@ -0,0 +1,1297 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ *
+ * This implements the un-subdivide algorithm, which generates a lower resolution base mesh and
+ * its corresponding grids to match a given original mesh.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_gsqueue.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_subdiv.h"
+#include "BKE_subsurf.h"
+
+#include "bmesh.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "multires_reshape.h"
+#include "multires_unsubdivide.h"
+
+/* This is done in the following steps:
+ *
+ * - If there are already grids in the original mesh,
+ * convert them from tangent displacement to object space coordinates.
+ * - Assign data-layers to the original mesh to map vertices to a new base mesh.
+ * These data-layers store the indices of the elements in the original mesh.
+ * This way the original indices are
+ * preserved when doing mesh modifications (removing and dissolving vertices)
+ * when building the new base mesh.
+ * - Try to find a lower resolution base mesh. This is done by flood fill operation that tags the
+ * center vertices of the lower level grid.
+ * If the algorithm can tag all vertices correctly,
+ * the lower level base mesh is generated by dissolving the tagged vertices.
+ * - Use the data-layers to map vertices from the base mesh to the original mesh and original to
+ * base mesh.
+ * - Find two adjacent vertices on the base mesh to a given vertex to map that loop from base mesh
+ * to original mesh
+ * - Extract the grid from the original mesh from that loop. If there are no grids in the original
+ * mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern
+ * over them. If there are grids in the original mesh, iterate in a grid pattern over the polys,
+ * reorder all the coordinates of the grid in that poly and copy those coordinates to the new
+ * base mesh grid.
+ * - Copy the new grid data over to a new allocated MDISP layer with the appropriate size to store
+ * the new levels.
+ * - Convert the grid data from object space to tangent displacement.
+ */
+
+/**
+ * Used to check if a vertex is in a disconnected element ID.
+ */
+static bool is_vertex_in_id(BMVert *v, int *elem_id, int elem)
+{
+ const int v_index = BM_elem_index_get(v);
+ return elem_id[v_index] == elem;
+}
+
+static bool is_vertex_pole_three(BMVert *v)
+{
+ return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3);
+}
+
+static bool is_vertex_pole(BMVert *v)
+{
+ return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3 || BM_vert_edge_count(v) >= 5);
+}
+
+/**
+ * Returns the first pole that is found in an element ID.
+ *
+ * Tries to give priority to 3 vert poles as they generally generate better results in cases were
+ * the un-subdivide solution is ambiguous.
+ */
+static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem)
+{
+ BMIter iter;
+ BMVert *v;
+ BMVert *pole = NULL;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole_three(v)) {
+ return v;
+ }
+ else if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole(v)) {
+ pole = v;
+ }
+ }
+ return pole;
+}
+
+/**
+ * Checks if the mesh is all quads.
+ *
+ * TODO(pablodp606): This can perform additional checks if they are faster than trying to search
+ * for an un-subdivide solution. This way it is possible to cancel the operation faster.
+ */
+static bool unsubdivide_is_all_quads(BMesh *bm)
+{
+ BMIter iter;
+ BMIter iter_a;
+ BMFace *f;
+ BMVert *v;
+ int count = 0;
+ if (bm->totface < 3) {
+ return false;
+ }
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ count = 0;
+ BM_ITER_ELEM (v, &iter_a, f, BM_VERTS_OF_FACE) {
+ count++;
+ }
+
+ if (count != 4) {
+ return false;
+ }
+ }
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_vert_is_wire(v)) {
+ return false;
+ }
+ if (BM_vert_edge_count(v) == 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Returns true if from_v and to_v, which should be part of the same quad face, are diagonals.
+ */
+static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v)
+{
+ return !BM_edge_exists(from_v, to_v);
+}
+
+/**
+ * Generates a possible solution for un-subdivision by tagging the (0,0)
+ * vertices of the possible grids.
+ *
+ * This works using a flood fill operation using the quads diagonals to jump to the next vertex.
+ *
+ * If initial_vertex is part of the base mesh solution, the flood fill should tag only the (0.0)
+ * vertices of the grids that need to be dissolved, and nothing else.
+ */
+static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex)
+{
+ bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices");
+ GSQueue *queue;
+ queue = BLI_gsqueue_new(sizeof(BMVert *));
+
+ /* Add and tag the vertices connected by a diagonal to initial_vertex to the flood fill queue. If
+ * initial_vertex is a pole and there is a valid solution, those vertices should be the (0,0) of
+ * the grids for the loops of initial_vertex. */
+ BMIter iter;
+ BMIter iter_a;
+ BMFace *f;
+ BMVert *neighbor_v;
+ BM_ITER_ELEM (f, &iter, initial_vertex, BM_FACES_OF_VERT) {
+ BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
+ int neighbor_vertex_index = BM_elem_index_get(neighbor_v);
+ if (neighbor_v != initial_vertex && is_vertex_diagonal(neighbor_v, initial_vertex)) {
+ BLI_gsqueue_push(queue, &neighbor_v);
+ visited_vertices[neighbor_vertex_index] = true;
+ BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true);
+ }
+ }
+ }
+
+ /* Repeat a similar operation for all vertices in the queue. */
+ /* In this case, add to the queue the vertices connected by 2 steps using the diagonals in any
+ * direction. If a solution exists and intial_vertex was a pole, this is guaranteed that will tag
+ * all the (0,0) vertices of the grids, and nothing else. */
+ /* If it was not a pole, it may or may not find a solution, even if the solution exists. */
+ while (!BLI_gsqueue_is_empty(queue)) {
+ BMVert *from_v;
+ BLI_gsqueue_pop(queue, &from_v);
+
+ /* Get the diagonals (first connected step) */
+ GSQueue *diagonals;
+ diagonals = BLI_gsqueue_new(sizeof(BMVert *));
+ BM_ITER_ELEM (f, &iter, from_v, BM_FACES_OF_VERT) {
+ BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
+ if (neighbor_v != from_v && is_vertex_diagonal(neighbor_v, from_v)) {
+ BLI_gsqueue_push(diagonals, &neighbor_v);
+ }
+ }
+ }
+
+ /* Do the second connected step. This vertices are the ones that are added to the flood fill
+ * queue. */
+ while (!BLI_gsqueue_is_empty(diagonals)) {
+ BMVert *diagonal_v;
+ BLI_gsqueue_pop(diagonals, &diagonal_v);
+ BM_ITER_ELEM (f, &iter, diagonal_v, BM_FACES_OF_VERT) {
+ BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
+ int neighbor_vertex_index = BM_elem_index_get(neighbor_v);
+ if (!visited_vertices[neighbor_vertex_index] && neighbor_v != diagonal_v &&
+ is_vertex_diagonal(neighbor_v, diagonal_v)) {
+ BLI_gsqueue_push(queue, &neighbor_v);
+ visited_vertices[neighbor_vertex_index] = true;
+ BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true);
+ }
+ }
+ }
+ }
+ BLI_gsqueue_free(diagonals);
+ }
+
+ BLI_gsqueue_free(queue);
+ MEM_freeN(visited_vertices);
+}
+
+/**
+ * This function checks if the current status of the #BMVert tags
+ * corresponds to a valid un-subdivide solution.
+ *
+ * This means that all vertices corresponding to the (0,0) grid coordinate should be tagged.
+ *
+ * On a valid solution, the following things should happen:
+ * - No boundary vertices should be tagged
+ * - No vertices connected by an edge or a quad diagonal to a tagged vertex should be tagged
+ * - All boundary vertices should have one vertex connected by an edge or a diagonal tagged
+ */
+static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int elem)
+{
+ BMVert *v, *neighbor_v;
+ BMIter iter, iter_a, iter_b;
+ BMFace *f;
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (is_vertex_in_id(v, elem_id, elem)) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ /* Tagged vertex in boundary */
+ if (BM_vert_is_boundary(v)) {
+ return false;
+ }
+ /* Tagged vertex with connected tagged vertex. */
+ BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
+ BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
+ return false;
+ }
+ }
+ }
+ }
+ if (BM_vert_is_boundary(v)) {
+ /* Un-tagged vertex in boundary without connected tagged vertices. */
+ bool any_tagged = false;
+ BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
+ BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
+ any_tagged = true;
+ }
+ }
+ }
+ if (!any_tagged) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Search and validates an un-subdivide solution for a given element ID.
+ */
+static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, int elem)
+{
+ /* First, get vertex candidates to try to generate possible un-subdivide solution. */
+ /* Find a vertex pole. If there is a solution on an all quad base mesh, this vertex should be
+ * part of the base mesh. If it isn't, then there is no solution. */
+ GSQueue *initial_vertex = BLI_gsqueue_new(sizeof(BMVert *));
+ BMVert *initial_vertex_pole = unsubdivide_find_any_pole(bm, elem_id, elem);
+ if (initial_vertex_pole != NULL) {
+ BLI_gsqueue_push(initial_vertex, &initial_vertex_pole);
+ }
+
+ /* Also try from the different 4 vertices of a quad in the current
+ * disconnected element ID. If a solution exists the search should return a valid solution from
+ * one of these vertices.*/
+ BMFace *f, *init_face = NULL;
+ BMVert *v;
+ BMIter iter_a, iter_b;
+ BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (is_vertex_in_id(v, elem_id, elem)) {
+ init_face = f;
+ break;
+ }
+ }
+ if (init_face != NULL) {
+ break;
+ }
+ }
+
+ BM_ITER_ELEM (v, &iter_a, init_face, BM_VERTS_OF_FACE) {
+ BLI_gsqueue_push(initial_vertex, &v);
+ }
+
+ bool valid_tag_found = false;
+
+ /* Check all vertex candidates to a solution. */
+ while (!BLI_gsqueue_is_empty(initial_vertex)) {
+
+ BMVert *iv;
+ BLI_gsqueue_pop(initial_vertex, &iv);
+
+ /* Generate a possible solution. */
+ unsubdivide_face_center_vertex_tag(bm, iv);
+
+ /* Check if the solution is valid. If it is, stop searching. */
+ if (unsubdivide_is_center_vertex_tag_valid(bm, elem_id, elem)) {
+ valid_tag_found = true;
+ break;
+ }
+
+ /* If the solution is not valid, reset the state of all tags in this disconnected element ID
+ * and try again. */
+ BMVert *v_reset;
+ BMIter iter;
+ BM_ITER_MESH (v_reset, &iter, bm, BM_VERTS_OF_MESH) {
+ if (is_vertex_in_id(v_reset, elem_id, elem)) {
+ BM_elem_flag_set(v_reset, BM_ELEM_TAG, false);
+ }
+ }
+ }
+ BLI_gsqueue_free(initial_vertex);
+ return valid_tag_found;
+}
+
+/**
+ * Uses a flood fill operation to generate a different ID for each disconnected mesh element.
+ */
+static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id)
+{
+ bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices");
+ int current_id = 0;
+ for (int i = 0; i < bm->totvert; i++) {
+ if (!visited_vertices[i]) {
+ GSQueue *queue;
+ queue = BLI_gsqueue_new(sizeof(BMVert *));
+
+ visited_vertices[i] = true;
+ elem_id[i] = current_id;
+ BMVert *iv = BM_vert_at_index(bm, i);
+ BLI_gsqueue_push(queue, &iv);
+
+ while (!BLI_gsqueue_is_empty(queue)) {
+ BMIter iter;
+ BMVert *current_v, *neighbor_v;
+ BMEdge *ed;
+ BLI_gsqueue_pop(queue, &current_v);
+ BM_ITER_ELEM (ed, &iter, current_v, BM_EDGES_OF_VERT) {
+ neighbor_v = BM_edge_other_vert(ed, current_v);
+ const int neighbor_index = BM_elem_index_get(neighbor_v);
+ if (!visited_vertices[neighbor_index]) {
+ visited_vertices[neighbor_index] = true;
+ elem_id[neighbor_index] = current_id;
+ BLI_gsqueue_push(queue, &neighbor_v);
+ }
+ }
+ }
+ current_id++;
+ BLI_gsqueue_free(queue);
+ }
+ }
+ MEM_freeN(visited_vertices);
+ return current_id;
+}
+
+/**
+ * Builds a base mesh one subdivision level down from the current original mesh if the original
+ * mesh has a valid solution stored in the #BMVert tags.
+ */
+static void unsubdivide_build_base_mesh_from_tags(BMesh *bm)
+{
+ BMVert *v;
+ BMIter iter;
+
+ /* Stores the vertices which correspond to (1, 0) and (0, 1) of the grids in the select flag. */
+ BM_mesh_elem_hflag_enable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ BMVert *v_neighbor;
+ BMIter iter_a;
+ BMEdge *ed;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_ELEM (ed, &iter_a, v, BM_EDGES_OF_VERT) {
+ v_neighbor = BM_edge_other_vert(ed, v);
+ if (BM_elem_flag_test(v_neighbor, BM_ELEM_TAG)) {
+ BM_elem_flag_set(v, BM_ELEM_SELECT, false);
+ }
+ }
+ }
+
+ /* Dissolves the (0,0) vertices of the grids. */
+ BMO_op_callf(bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_TAG,
+ false,
+ true);
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+
+ /* Copy the select flag to the tag flag. */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, true);
+ }
+ }
+
+ /* Dissolves the (1,0) and (0,1) vertices of the grids. */
+ BMO_op_callf(bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_TAG,
+ false,
+ true);
+}
+
+/**
+ * Main function to get a base mesh one level down from the current original mesh if it exists.
+ *
+ * This searches for different un-subdivide solutions and stores them as a combination of #BMVert
+ * flags for each disconnected mesh element.
+ *
+ * If the solution for all elements are valid, it builds a new base mesh based on those tags by
+ * dissolving and merging vertices.
+ */
+static bool multires_unsubdivide_single_level(BMesh *bm)
+{
+
+ /* Do a first check to make sure that it makes sense to search for un-subdivision in this mesh.
+ */
+ if (!unsubdivide_is_all_quads(bm)) {
+ return false;
+ };
+
+ /* Initialize the vertex table. */
+ BM_mesh_elem_table_init(bm, BM_VERT);
+ BM_mesh_elem_table_ensure(bm, BM_VERT);
+
+ /* Build disconnected elements IDs. Each disconnected mesh element is evaluated separately. */
+ int *elem_id = MEM_calloc_arrayN(sizeof(int), bm->totvert, " ELEM ID");
+ const int tot_ids = unsubdivide_init_elem_ids(bm, elem_id);
+
+ bool valid_tag_found = true;
+
+ /* Reset the #BMesh flags as they are used to store data during the un-subdivide process. */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ /* For each disconnected mesh element ID, search if an un-subdivide solution is possible. The
+ * whole un-subdivide process fails if a single disconnected mesh element fails. */
+ for (int id = 0; id < tot_ids; id++) {
+ /* Try to the #BMesh vertex flag tags corresponding to an un-subdivide solution. */
+ if (!unsubdivide_tag_disconnected_mesh_element(bm, elem_id, id)) {
+ valid_tag_found = false;
+ break;
+ }
+ }
+
+ /* If a solution was found for all elements IDs, build the new base mesh using the solution
+ * stored in the BMVert tags. */
+ if (valid_tag_found) {
+ unsubdivide_build_base_mesh_from_tags(bm);
+ }
+
+ MEM_freeN(elem_id);
+ return valid_tag_found;
+}
+
+/**
+ * Returns the next edge and vertex in the direction of a given edge.
+ */
+static BMEdge *edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex)
+{
+ BMIter iter;
+ BMEdge *test_edge;
+ if (edge == NULL) {
+ (*r_next_vertex) = v;
+ return edge;
+ }
+ (*r_next_vertex) = BM_edge_other_vert(edge, v);
+ BM_ITER_ELEM (test_edge, &iter, (*r_next_vertex), BM_EDGES_OF_VERT) {
+ if (!BM_edge_share_quad_check(test_edge, edge)) {
+ return test_edge;
+ }
+ }
+ return NULL;
+}
+
+static BMFace *face_step(BMEdge *edge, BMFace *f)
+{
+ BMIter iter;
+ BMFace *face_iter;
+
+ BM_ITER_ELEM (face_iter, &iter, edge, BM_FACES_OF_EDGE) {
+ if (BM_face_share_edge_check(face_iter, f)) {
+ return face_iter;
+ }
+ }
+ return f;
+}
+
+/**
+ * Returns the other edge which belongs to the face f which is different from edge_x and shares
+ * initial_vertex.
+ */
+static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex)
+{
+ BMIter iter;
+ BMEdge *test_edge;
+ BM_ITER_ELEM (test_edge, &iter, f, BM_EDGES_OF_FACE) {
+ if (edge_x != test_edge) {
+ if (test_edge->v1 != initial_vertex && test_edge->v2 == initial_vertex) {
+ return test_edge;
+ }
+ if (test_edge->v2 != initial_vertex && test_edge->v1 == initial_vertex) {
+ return test_edge;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Writes the current mdisp data into the corresponding area of quad poly giving its corner's loop.
+ */
+static void write_loop_in_face_grid(
+ float (*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop)
+{
+ int origin[2];
+ int step_x[2];
+ int step_y[2];
+
+ const int grid_offset = orig_grid_size - 1;
+ origin[0] = grid_offset;
+ origin[1] = grid_offset;
+
+ switch (loop) {
+ case 0:
+ step_x[0] = -1;
+ step_x[1] = 0;
+
+ step_y[0] = 0;
+ step_y[1] = -1;
+
+ break;
+ case 1:
+ step_x[0] = 0;
+ step_x[1] = 1;
+
+ step_y[0] = -1;
+ step_y[1] = -0;
+ break;
+ case 2:
+ step_x[0] = 1;
+ step_x[1] = 0;
+
+ step_y[0] = 0;
+ step_y[1] = 1;
+ break;
+ case 3:
+ step_x[0] = 0;
+ step_x[1] = -1;
+
+ step_y[0] = 1;
+ step_y[1] = 0;
+ break;
+ default:
+ BLI_assert(!"Should never happen");
+ break;
+ }
+
+ for (int y = 0; y < orig_grid_size; y++) {
+ for (int x = 0; x < orig_grid_size; x++) {
+ const int remap_x = origin[1] + (step_x[1] * x) + (step_y[1] * y);
+ const int remap_y = origin[0] + (step_x[0] * x) + (step_y[0] * y);
+
+ const int final_index = remap_x + remap_y * face_grid_size;
+ copy_v3_v3(face_grid[final_index], mdisp->disps[x + y * orig_grid_size]);
+ }
+ }
+}
+
+/**
+ * Writes a buffer containing the 4 grids in the correct orientation of the 4 loops of a face into
+ * the main #MultiresUnsubdivideGrid that is being extracted.
+ */
+static void write_face_grid_in_unsubdivide_grid(MultiresUnsubdivideGrid *grid,
+ float (*face_grid)[3],
+ int face_grid_size,
+ int gunsub_x,
+ int gunsub_y)
+{
+ const int grid_it = face_grid_size - 1;
+ for (int y = 0; y < face_grid_size; y++) {
+ for (int x = 0; x < face_grid_size; x++) {
+ const int remap_x = (grid_it * gunsub_x) + x;
+ const int remap_y = (grid_it * gunsub_y) + y;
+
+ const int remap_index_y = grid->grid_size - remap_x - 1;
+ const int remap_index_x = grid->grid_size - remap_y - 1;
+ const int grid_index = remap_index_x + (remap_index_y * grid->grid_size);
+ copy_v3_v3(grid->grid_co[grid_index], face_grid[x + y * face_grid_size]);
+ }
+ }
+}
+
+/**
+ * Stores the data from the mdisps grids of the loops of the face f
+ * into the new grid for the new base mesh.
+ *
+ * Used when there are already grids in the original mesh.
+ */
+static void store_grid_data(MultiresUnsubdivideContext *context,
+ MultiresUnsubdivideGrid *grid,
+ BMVert *v,
+ BMFace *f,
+ int grid_x,
+ int grid_y)
+{
+
+ Mesh *original_mesh = context->original_mesh;
+ MPoly *poly = &original_mesh->mpoly[BM_elem_index_get(f)];
+
+ const int corner_vertex_index = BM_elem_index_get(v);
+
+ /* Calculates an offset to write the grids correctly oriented in the main
+ * #MultiresUnsubdivideGrid. */
+ int loop_offset = 0;
+ for (int i = 0; i < poly->totloop; i++) {
+ const int loop_index = poly->loopstart + i;
+ MLoop *l = &original_mesh->mloop[loop_index];
+ if (l->v == corner_vertex_index) {
+ loop_offset = i;
+ break;
+ }
+ }
+
+ /* Write the 4 grids of the current quad with the right orientation into the face_grid buffer. */
+ const int grid_size = BKE_ccg_gridsize(context->num_original_levels);
+ const int face_grid_size = BKE_ccg_gridsize(context->num_original_levels + 1);
+ const int face_grid_area = face_grid_size * face_grid_size;
+ float(*face_grid)[3] = MEM_calloc_arrayN(face_grid_area, 3 * sizeof(float), "face_grid");
+
+ for (int i = 0; i < poly->totloop; i++) {
+ const int loop_index = poly->loopstart + i;
+ MDisps *mdisp = &context->original_mdisp[loop_index];
+ int quad_loop = i - loop_offset;
+ if (quad_loop < 0) {
+ quad_loop += 4;
+ }
+ if (quad_loop >= 4) {
+ quad_loop -= 4;
+ }
+ write_loop_in_face_grid(face_grid, mdisp, face_grid_size, grid_size, quad_loop);
+ }
+
+ /* Write the face_grid buffer in the correct position in the #MultiresUnsubdivideGrids that is
+ * being extracted. */
+ write_face_grid_in_unsubdivide_grid(grid, face_grid, face_grid_size, grid_x, grid_y);
+
+ MEM_freeN(face_grid);
+}
+
+/**
+ * Stores the data into the new grid from a #BMVert.
+ * Used when there are no grids in the original mesh.
+ */
+static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y)
+{
+ const int remap_index_y = grid->grid_size - 1 - grid_x;
+ const int remap_index_x = grid->grid_size - 1 - grid_y;
+
+ const int grid_index = remap_index_x + (remap_index_y * grid->grid_size);
+
+ copy_v3_v3(grid->grid_co[grid_index], v->co);
+}
+
+/**
+ * Main function to extract data from the original bmesh and MDISPS as grids for the new base mesh.
+ */
+static void multires_unsubdivide_extract_single_grid_from_face_edge(
+ MultiresUnsubdivideContext *context,
+ BMFace *f1,
+ BMEdge *e1,
+ bool flip_grid,
+ MultiresUnsubdivideGrid *grid)
+{
+ BMVert *initial_vertex;
+ BMEdge *initial_edge_x;
+ BMEdge *initial_edge_y;
+
+ const int grid_size = BKE_ccg_gridsize(context->num_new_levels);
+ const int unsubdiv_grid_size = grid->grid_size = BKE_ccg_gridsize(context->num_total_levels);
+ grid->grid_size = unsubdiv_grid_size;
+ grid->grid_co = MEM_calloc_arrayN(
+ unsubdiv_grid_size * unsubdiv_grid_size, 3 * sizeof(float), "grids coordinates");
+
+ /* Get the vertex on the corner of the grid. This vertex was tagged previously as it also exist
+ * on the base mesh. */
+ initial_edge_x = e1;
+ if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) {
+ initial_vertex = initial_edge_x->v1;
+ }
+ else {
+ initial_vertex = initial_edge_x->v2;
+ }
+
+ /* From that vertex, get the edge that defines the grid Y axis for extraction. */
+ initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex);
+
+ if (flip_grid) {
+ BMEdge *edge_temp;
+ edge_temp = initial_edge_x;
+ initial_edge_x = initial_edge_y;
+ initial_edge_y = edge_temp;
+ }
+
+ int grid_x = 0;
+ int grid_y = 0;
+
+ BMVert *current_vertex_x = initial_vertex;
+ BMEdge *edge_x = initial_edge_x;
+
+ BMVert *current_vertex_y = initial_vertex;
+ BMEdge *edge_y = initial_edge_y;
+ BMEdge *prev_edge_y = initial_edge_y;
+
+ BMFace *current_face = f1;
+ BMFace *grid_face = f1;
+
+ /* If the data is going to be extracted from the already existing grids, there is no need to go
+ * to the last vertex of the iteration as that coordinate is also included in the grids
+ * corresponding to the loop of the face of the previous iteration. */
+ int grid_iteration_max_steps = grid_size;
+ if (context->num_original_levels > 0) {
+ grid_iteration_max_steps = grid_size - 1;
+ }
+
+ /* Iterate over the mesh vertices in a grid pattern using the axis defined by the two initial
+ * edges. */
+ while (grid_y < grid_iteration_max_steps) {
+
+ grid_face = current_face;
+
+ while (grid_x < grid_iteration_max_steps) {
+ if (context->num_original_levels == 0) {
+ /* If there were no grids on the original mesh, extract the data directly from the
+ * vertices. */
+ store_vertex_data(grid, current_vertex_x, grid_x, grid_y);
+ edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
+ }
+ else {
+ /* If there were grids in the original mesh, extract the data from the grids and iterate
+ * over the faces. */
+ store_grid_data(context, grid, current_vertex_x, grid_face, grid_x, grid_y);
+ edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
+ grid_face = face_step(edge_x, grid_face);
+ }
+
+ grid_x++;
+ }
+ grid_x = 0;
+
+ edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
+ current_vertex_x = current_vertex_y;
+
+ /* Get the next edge_x to extract the next row of the grid. This needs to be done because there
+ * may be two edges connected to current_vertex_x that belong to two different grids. */
+ BMIter iter;
+ BMEdge *ed;
+ BMFace *f;
+ BM_ITER_ELEM (ed, &iter, current_vertex_x, BM_EDGES_OF_VERT) {
+ if (ed != prev_edge_y && BM_edge_in_face(ed, current_face)) {
+ edge_x = ed;
+ break;
+ }
+ }
+ BM_ITER_ELEM (f, &iter, edge_x, BM_FACES_OF_EDGE) {
+ if (f != current_face) {
+ current_face = f;
+ break;
+ }
+ }
+
+ prev_edge_y = edge_y;
+ grid_y++;
+ }
+}
+
+/**
+ * Returns the l+1 and l-1 vertices of the base mesh poly were the grid from the face f1 and edge
+ * e1 is going to be extracted.
+ *
+ * These vertices should always have an corresponding existing vertex on the base mesh.
+ */
+static void multires_unsubdivide_get_grid_corners_on_base_mesh(BMFace *f1,
+ BMEdge *e1,
+ BMVert **r_corner_x,
+ BMVert **r_corner_y)
+{
+ BMVert *initial_vertex;
+ BMEdge *initial_edge_x;
+ BMEdge *initial_edge_y;
+
+ initial_edge_x = e1;
+ if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) {
+ initial_vertex = initial_edge_x->v1;
+ }
+ else {
+ initial_vertex = initial_edge_x->v2;
+ }
+
+ /* From that vertex, get the edge that defines the grid Y axis for extraction. */
+ initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex);
+
+ BMVert *current_vertex_x = initial_vertex;
+ BMEdge *edge_x = initial_edge_x;
+
+ BMVert *current_vertex_y = initial_vertex;
+ BMEdge *edge_y = initial_edge_y;
+
+ /* Do an edge step until it finds a tagged vertex, which is part of the base mesh. */
+ /* x axis */
+ edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
+ while (!BM_elem_flag_test(current_vertex_x, BM_ELEM_TAG)) {
+ edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
+ }
+ (*r_corner_x) = current_vertex_x;
+
+ /* Same for y axis */
+ edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
+ while (!BM_elem_flag_test(current_vertex_y, BM_ELEM_TAG)) {
+ edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
+ }
+ (*r_corner_y) = current_vertex_y;
+}
+
+static BMesh *get_bmesh_from_mesh(Mesh *mesh)
+{
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ BMesh *bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ return bm;
+}
+
+/* Data-layer names to store the original indices of the elements before modifying the mesh. */
+static const char lname[] = "l_remap_index";
+static const char vname[] = "v_remap_index";
+
+static void multires_unsubdivide_free_original_datalayers(Mesh *mesh)
+{
+ const int l_layer_index = CustomData_get_named_layer_index(&mesh->ldata, CD_PROP_INT, lname);
+ if (l_layer_index != -1) {
+ CustomData_free_layer(&mesh->ldata, CD_PROP_INT, mesh->totloop, l_layer_index);
+ }
+
+ const int v_layer_index = CustomData_get_named_layer_index(&mesh->vdata, CD_PROP_INT, vname);
+ if (v_layer_index != -1) {
+ CustomData_free_layer(&mesh->vdata, CD_PROP_INT, mesh->totvert, v_layer_index);
+ }
+}
+
+/**
+ * Generates two data-layers to map loops and vertices from base mesh to original mesh after
+ * dissolving the vertices.
+ */
+static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh)
+{
+ multires_unsubdivide_free_original_datalayers(mesh);
+
+ int *l_index = CustomData_add_layer_named(
+ &mesh->ldata, CD_PROP_INT, CD_CALLOC, NULL, mesh->totloop, lname);
+
+ int *v_index = CustomData_add_layer_named(
+ &mesh->vdata, CD_PROP_INT, CD_CALLOC, NULL, mesh->totvert, vname);
+
+ /* Initialize these data-layer with the indices in the current mesh. */
+ for (int i = 0; i < mesh->totloop; i++) {
+ l_index[i] = i;
+ }
+ for (int i = 0; i < mesh->totvert; i++) {
+ v_index[i] = i;
+ }
+}
+
+static void multires_unsubdivide_prepare_original_bmesh_for_extract(
+ MultiresUnsubdivideContext *context)
+{
+
+ Mesh *original_mesh = context->original_mesh;
+ Mesh *base_mesh = context->base_mesh;
+
+ BMesh *bm_original_mesh = context->bm_original_mesh = get_bmesh_from_mesh(original_mesh);
+
+ /* Initialize the elem tables. */
+ BM_mesh_elem_table_ensure(bm_original_mesh, BM_EDGE);
+ BM_mesh_elem_table_ensure(bm_original_mesh, BM_FACE);
+ BM_mesh_elem_table_ensure(bm_original_mesh, BM_VERT);
+
+ /* Disable all flags. */
+ BM_mesh_elem_hflag_disable_all(
+ bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_mesh_elem_hflag_disable_all(
+ bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ /* Get the mapping data-layer. */
+ context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT, vname);
+
+ /* Tag the base mesh vertices in the original mesh. */
+ for (int i = 0; i < base_mesh->totvert; i++) {
+ int vert_basemesh_index = context->base_to_orig_vmap[i];
+ BMVert *v = BM_vert_at_index(bm_original_mesh, vert_basemesh_index);
+ BM_elem_flag_set(v, BM_ELEM_TAG, true);
+ }
+
+ /* Create a map from loop index to poly index for the original mesh. */
+ context->loop_to_face_map = MEM_calloc_arrayN(sizeof(int), original_mesh->totloop, "loop map");
+
+ for (int i = 0; i < original_mesh->totpoly; i++) {
+ MPoly *poly = &original_mesh->mpoly[i];
+ for (int l = 0; l < poly->totloop; l++) {
+ int original_loop_index = l + poly->loopstart;
+ context->loop_to_face_map[original_loop_index] = i;
+ }
+ }
+}
+
+/**
+ * Checks the orientation of the loops to flip the x and y axis when extracting the grid if
+ * necessary.
+ */
+static bool multires_unsubdivide_flip_grid_x_axis(Mesh *mesh, int poly, int loop, int v_x)
+{
+ MPoly *p = &mesh->mpoly[poly];
+
+ MLoop *l_first = &mesh->mloop[p->loopstart];
+ if ((loop == (p->loopstart + (p->totloop - 1))) && l_first->v == v_x) {
+ return true;
+ }
+
+ int next_l_index = loop + 1;
+ if (next_l_index < p->loopstart + p->totloop) {
+ MLoop *l_next = &mesh->mloop[next_l_index];
+ if (l_next->v == v_x) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *context)
+{
+ Mesh *original_mesh = context->original_mesh;
+ Mesh *base_mesh = context->base_mesh;
+
+ BMesh *bm_original_mesh = context->bm_original_mesh;
+
+ context->num_grids = base_mesh->totloop;
+ context->base_mesh_grids = MEM_calloc_arrayN(
+ sizeof(MultiresUnsubdivideGrid), base_mesh->totloop, "grids");
+
+ /* Based on the existing indices in the data-layers, generate two vertex indices maps. */
+ /* From vertex index in original to vertex index in base and from vertex index in base to vertex
+ * index in original. */
+ int *orig_to_base_vmap = MEM_calloc_arrayN(sizeof(int), bm_original_mesh->totvert, "orig vmap");
+ int *base_to_orig_vmap = MEM_calloc_arrayN(sizeof(int), base_mesh->totvert, "base vmap");
+
+ context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT, vname);
+ for (int i = 0; i < base_mesh->totvert; i++) {
+ base_to_orig_vmap[i] = context->base_to_orig_vmap[i];
+ }
+
+ /* If an index in original does not exist in base (it was dissolved when creating the new base
+ * mesh, return -1. */
+ for (int i = 0; i < original_mesh->totvert; i++) {
+ orig_to_base_vmap[i] = -1;
+ }
+
+ for (int i = 0; i < base_mesh->totvert; i++) {
+ const int orig_vertex_index = context->base_to_orig_vmap[i];
+ orig_to_base_vmap[orig_vertex_index] = i;
+ }
+
+ /* Add the original data-layers to the base mesh to have the loop indices stored in a data-layer,
+ * so they can be used from #BMesh. */
+ multires_unsubdivide_add_original_index_datalayers(base_mesh);
+
+ const int base_l_layer_index = CustomData_get_named_layer_index(
+ &base_mesh->ldata, CD_PROP_INT, lname);
+ BMesh *bm_base_mesh = get_bmesh_from_mesh(base_mesh);
+ BMIter iter, iter_a, iter_b;
+ BMVert *v;
+ BMLoop *l, *lb;
+
+ BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT);
+ BM_mesh_elem_table_ensure(bm_base_mesh, BM_FACE);
+
+ /* Get the data-layer that contains the loops indices. */
+ const int base_l_offset = CustomData_get_n_offset(
+ &bm_base_mesh->ldata, CD_PROP_INT, base_l_layer_index);
+
+ /* Main loop for extracting the grids. Iterates over the base mesh vertices. */
+ BM_ITER_MESH (v, &iter, bm_base_mesh, BM_VERTS_OF_MESH) {
+
+ /* For each base mesh vertex, get the corresponding #BMVert of the original mesh using the
+ * vertex map. */
+ const int orig_vertex_index = base_to_orig_vmap[BM_elem_index_get(v)];
+ BMVert *vert_original = BM_vert_at_index(bm_original_mesh, orig_vertex_index);
+
+ /* Iterate over the loops of that vertex in the original mesh. */
+ BM_ITER_ELEM (l, &iter_a, vert_original, BM_LOOPS_OF_VERT) {
+ /* For each loop, get the two vertices that should map to the l+1 and l-1 vertices in the
+ * base mesh of the poly of grid that is going to be extracted. */
+ BMVert *corner_x, *corner_y;
+ multires_unsubdivide_get_grid_corners_on_base_mesh(l->f, l->e, &corner_x, &corner_y);
+
+ /* Map the two obtained vertices to the base mesh. */
+ const int corner_x_index = orig_to_base_vmap[BM_elem_index_get(corner_x)];
+ const int corner_y_index = orig_to_base_vmap[BM_elem_index_get(corner_y)];
+
+ /* Iterate over the loops of the same vertex in the base mesh. With the previously obtained
+ * vertices and the current vertex it is possible to get the index of the loop in the base
+ * mesh the grid that is going to be extracted belongs to. */
+ BM_ITER_ELEM (lb, &iter_b, v, BM_LOOPS_OF_VERT) {
+ BMFace *base_face = lb->f;
+ BMVert *base_corner_x = BM_vert_at_index(bm_base_mesh, corner_x_index);
+ BMVert *base_corner_y = BM_vert_at_index(bm_base_mesh, corner_y_index);
+ /* If this is the correct loop in the base mesh, the original vertex and the two corners
+ * should be in the loop's face. */
+ if (BM_vert_in_face(base_corner_x, base_face) &&
+ BM_vert_in_face(base_corner_y, base_face)) {
+ /* Get the index of the loop. */
+ const int base_mesh_loop_index = BM_ELEM_CD_GET_INT(lb, base_l_offset);
+ const int base_mesh_face_index = BM_elem_index_get(base_face);
+
+ /* Check the orientation of the loops in case that is needed to flip the x and y axis
+ * when extracting the grid. */
+ const bool flip_grid = multires_unsubdivide_flip_grid_x_axis(
+ base_mesh, base_mesh_face_index, base_mesh_loop_index, corner_x_index);
+
+ /* Extract the grid for that loop. */
+ context->base_mesh_grids[base_mesh_loop_index].grid_index = base_mesh_loop_index;
+ multires_unsubdivide_extract_single_grid_from_face_edge(
+ context, l->f, l->e, !flip_grid, &context->base_mesh_grids[base_mesh_loop_index]);
+
+ break;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(orig_to_base_vmap);
+ MEM_freeN(base_to_orig_vmap);
+
+ BM_mesh_free(bm_base_mesh);
+ multires_unsubdivide_free_original_datalayers(base_mesh);
+}
+
+static void multires_unsubdivide_private_extract_data_free(MultiresUnsubdivideContext *context)
+{
+ if (context->bm_original_mesh != NULL) {
+ BM_mesh_free(context->bm_original_mesh);
+ }
+ MEM_SAFE_FREE(context->loop_to_face_map);
+}
+
+void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context,
+ Mesh *original_mesh,
+ struct MultiresModifierData *mmd)
+{
+ context->original_mesh = original_mesh;
+ context->num_new_levels = 0;
+ context->num_total_levels = 0;
+ context->num_original_levels = mmd->totlvl;
+}
+
+bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context)
+{
+ Mesh *original_mesh = context->original_mesh;
+
+ /* Prepare the data-layers to map base to original. */
+ multires_unsubdivide_add_original_index_datalayers(original_mesh);
+ BMesh *bm_base_mesh = get_bmesh_from_mesh(original_mesh);
+
+ /* Un-subdivide as many iterations as possible. */
+ context->num_new_levels = 0;
+ int num_levels_left = context->max_new_levels;
+ while (num_levels_left > 0 && multires_unsubdivide_single_level(bm_base_mesh)) {
+ context->num_new_levels++;
+ num_levels_left--;
+ }
+
+ /* If no un-subdivide steps were possible, free the bmesh, the map data-layers and stop. */
+ if (context->num_new_levels == 0) {
+ multires_unsubdivide_free_original_datalayers(original_mesh);
+ BM_mesh_free(bm_base_mesh);
+ return false;
+ }
+
+ /* Calculate the final levels for the new grids over base mesh. */
+ context->num_total_levels = context->num_new_levels + context->num_original_levels;
+
+ /* Store the new base-mesh as a mesh in context, free bmesh. */
+ context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
+ BM_mesh_bm_to_me(NULL,
+ bm_base_mesh,
+ context->base_mesh,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = true,
+ }));
+ BM_mesh_free(bm_base_mesh);
+
+ /* Initialize bmesh and maps for the original mesh and extract the grids. */
+
+ multires_unsubdivide_prepare_original_bmesh_for_extract(context);
+ multires_unsubdivide_extract_grids(context);
+
+ return true;
+}
+
+void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context)
+{
+ multires_unsubdivide_private_extract_data_free(context);
+ for (int i = 0; i < context->num_grids; i++) {
+ if (context->base_mesh_grids[i].grid_size > 0) {
+ MEM_SAFE_FREE(context->base_mesh_grids[i].grid_co);
+ }
+ }
+ MEM_SAFE_FREE(context->base_mesh_grids);
+}
+
+/**
+ * This function allocates new mdisps with the right size to fit the new extracted grids from the
+ * base mesh and copies the data to them.
+ */
+static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideContext *context,
+ Mesh *base_mesh)
+{
+ /* Free the current MDISPS and create a new ones. */
+ if (CustomData_has_layer(&base_mesh->ldata, CD_MDISPS)) {
+ CustomData_free_layers(&base_mesh->ldata, CD_MDISPS, base_mesh->totloop);
+ }
+ MDisps *mdisps = CustomData_add_layer(
+ &base_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, base_mesh->totloop);
+
+ const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2);
+ const int totloop = base_mesh->totloop;
+
+ BLI_assert(base_mesh->totloop == context->num_grids);
+
+ /* Allocate the MDISPS grids and copy the extracted data from context. */
+ for (int i = 0; i < totloop; i++) {
+ float(*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps");
+
+ if (mdisps[i].disps) {
+ MEM_freeN(mdisps[i].disps);
+ }
+
+ for (int j = 0; j < totdisp; j++) {
+ if (context->base_mesh_grids[i].grid_co) {
+ copy_v3_v3(disps[j], context->base_mesh_grids[i].grid_co[j]);
+ }
+ }
+
+ mdisps[i].disps = disps;
+ mdisps[i].totdisp = totdisp;
+ mdisps[i].level = context->num_total_levels;
+ }
+}
+
+int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
+ struct Object *object,
+ struct MultiresModifierData *mmd,
+ int rebuild_limit,
+ bool switch_view_to_lower_level)
+{
+ Mesh *mesh = object->data;
+
+ multires_force_sculpt_rebuild(object);
+
+ MultiresUnsubdivideContext unsubdiv_context = {0};
+ MultiresReshapeContext reshape_context = {0};
+
+ multires_unsubdivide_context_init(&unsubdiv_context, mesh, mmd);
+
+ /* Convert and store the existing grids in object space if available. */
+ if (mmd->totlvl != 0) {
+ if (!multires_reshape_context_create_from_object(&reshape_context, depsgraph, object, mmd)) {
+ return 0;
+ }
+
+ multires_reshape_store_original_grids(&reshape_context);
+ multires_reshape_assign_final_coords_from_mdisps(&reshape_context);
+ unsubdiv_context.original_mdisp = reshape_context.mdisps;
+ }
+
+ /* Set the limit for the levels that should be rebuild. */
+ unsubdiv_context.max_new_levels = rebuild_limit;
+
+ /* Un-subdivide and create the data for the new grids. */
+ if (multires_unsubdivide_to_basemesh(&unsubdiv_context) == 0) {
+ /* If there was no possible to rebuild any level, free the data and return. */
+ if (mmd->totlvl != 0) {
+ multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
+ multires_unsubdivide_context_free(&unsubdiv_context);
+ }
+ multires_reshape_context_free(&reshape_context);
+ return 0;
+ }
+
+ /* Free the reshape context used to convert the data from the original grids to object space. */
+ if (mmd->totlvl != 0) {
+ multires_reshape_context_free(&reshape_context);
+ }
+
+ /* Copy the new base mesh to the original mesh. */
+ BKE_mesh_nomain_to_mesh(unsubdiv_context.base_mesh, object->data, object, &CD_MASK_MESH, true);
+ Mesh *base_mesh = object->data;
+ multires_create_grids_in_unsubdivided_base_mesh(&unsubdiv_context, base_mesh);
+
+ /* Update the levels in the modifier. Force always to display at level 0 as it contains the new
+ * created level. */
+ mmd->totlvl = (char)unsubdiv_context.num_total_levels;
+
+ if (switch_view_to_lower_level) {
+ mmd->sculptlvl = 0;
+ mmd->lvl = 0;
+ }
+ else {
+ mmd->sculptlvl = (char)(mmd->sculptlvl + unsubdiv_context.num_new_levels);
+ mmd->lvl = (char)(mmd->lvl + unsubdiv_context.num_new_levels);
+ }
+
+ mmd->renderlvl = (char)(mmd->renderlvl + unsubdiv_context.num_new_levels);
+
+ /* Create a reshape context to convert the MDISPS data to tangent displacement. It can be the
+ * same as the previous one as a new Subdivision needs to be created for the new base mesh. */
+ if (!multires_reshape_context_create_from_base_mesh(&reshape_context, depsgraph, object, mmd)) {
+ return 0;
+ }
+ multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
+ multires_reshape_context_free(&reshape_context);
+
+ /* Free the un-subdivide context and return the total number of levels that were rebuild. */
+ const int rebuild_subdvis = unsubdiv_context.num_new_levels;
+ multires_unsubdivide_context_free(&unsubdiv_context);
+
+ return rebuild_subdvis;
+}
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.h b/source/blender/blenkernel/intern/multires_unsubdivide.h
new file mode 100644
index 00000000000..55d425c08bc
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.h
@@ -0,0 +1,94 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifndef __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__
+#define __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__
+
+#include "BLI_sys_types.h"
+
+struct BMesh;
+struct Depsgraph;
+struct Mesh;
+struct MultiresModifierData;
+struct Object;
+
+typedef struct MultiresUnsubdivideGrid {
+ /* For sanity checks. */
+ int grid_index;
+ int grid_size;
+
+ /** Grid coordinates in object space. */
+ float (*grid_co)[3];
+
+} MultiresUnsubdivideGrid;
+
+typedef struct MultiresUnsubdivideContext {
+ /* Input Mesh to un-subdivide. */
+ struct Mesh *original_mesh;
+ struct MDisps *original_mdisp;
+
+ /** Number of subdivision in the grids of the input mesh. */
+ int num_original_levels;
+
+ /** Level 0 base mesh after applying the maximum amount of unsubdivisions. */
+ struct Mesh *base_mesh;
+
+ /** Limit on how many levels down the unsubdivide operation should create, if possible. */
+ int max_new_levels;
+
+ /** New levels that were created after unsubdividing. */
+ int num_new_levels;
+
+ /**
+ * Number of subdivisions that should be applied to the base mesh.
+ * (num_new_levels + num_original_levels).
+ */
+ int num_total_levels;
+
+ /** Data for the new grids, indexed by base mesh loop index. */
+ int num_grids;
+ struct MultiresUnsubdivideGrid *base_mesh_grids;
+
+ /* Private data. */
+ struct BMesh *bm_original_mesh;
+ int *loop_to_face_map;
+ int *base_to_orig_vmap;
+} MultiresUnsubdivideContext;
+
+/* --------------------------------------------------------------------
+ * Construct/destruct reshape context.
+ */
+
+void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context,
+ struct Mesh *original_mesh,
+ struct MultiresModifierData *mmd);
+void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context);
+
+/* --------------------------------------------------------------------
+ * Rebuild Lower Subdivisions.
+ */
+
+/* Rebuilds all subdivision to the level 0 base mesh. */
+bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context);
+
+#endif /* __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__ */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index c3c538f3424..e6547012b88 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -37,6 +37,7 @@
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
@@ -66,7 +67,9 @@
#include "NOD_common.h"
#include "NOD_composite.h"
+#include "NOD_function.h"
#include "NOD_shader.h"
+#include "NOD_simulation.h"
#include "NOD_socket.h"
#include "NOD_texture.h"
@@ -86,7 +89,9 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo);
static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag);
static void free_localized_node_groups(bNodeTree *ntree);
static void node_free_node(bNodeTree *ntree, bNode *node);
-static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock);
+static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
+ bNodeSocket *sock,
+ const bool do_id_user);
static void ntree_init_data(ID *id)
{
@@ -229,12 +234,12 @@ static void ntree_free_data(ID *id)
/* free interface sockets */
for (sock = ntree->inputs.first; sock; sock = nextsock) {
nextsock = sock->next;
- node_socket_interface_free(ntree, sock);
+ node_socket_interface_free(ntree, sock, false);
MEM_freeN(sock);
}
for (sock = ntree->outputs.first; sock; sock = nextsock) {
nextsock = sock->next;
- node_socket_interface_free(ntree, sock);
+ node_socket_interface_free(ntree, sock, false);
MEM_freeN(sock);
}
@@ -744,6 +749,66 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
return sock;
}
+static void socket_id_user_increment(bNodeSocket *sock)
+{
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ id_us_plus(&default_value->value->id);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ id_us_plus(&default_value->value->id);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+}
+
+static void socket_id_user_decrement(bNodeSocket *sock)
+{
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ id_us_min(&default_value->value->id);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ id_us_min(&default_value->value->id);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+}
+
void nodeModifySocketType(
bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, int type, int subtype)
{
@@ -755,6 +820,7 @@ void nodeModifySocketType(
}
if (sock->default_value) {
+ socket_id_user_decrement(sock);
MEM_freeN(sock->default_value);
sock->default_value = NULL;
}
@@ -858,6 +924,18 @@ const char *nodeStaticSocketType(int type, int subtype)
return "NodeSocketString";
case SOCK_SHADER:
return "NodeSocketShader";
+ case SOCK_OBJECT:
+ return "NodeSocketObject";
+ case SOCK_IMAGE:
+ return "NodeSocketImage";
+ case SOCK_EMITTERS:
+ return "NodeSocketEmitters";
+ case SOCK_EVENTS:
+ return "NodeSocketEvents";
+ case SOCK_FORCES:
+ return "NodeSocketForces";
+ case SOCK_CONTROL_FLOW:
+ return "NodeSocketControlFlow";
}
return NULL;
}
@@ -919,6 +997,18 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype)
return "NodeSocketInterfaceString";
case SOCK_SHADER:
return "NodeSocketInterfaceShader";
+ case SOCK_OBJECT:
+ return "NodeSocketInterfaceObject";
+ case SOCK_IMAGE:
+ return "NodeSocketInterfaceImage";
+ case SOCK_EMITTERS:
+ return "NodeSocketInterfaceEmitters";
+ case SOCK_EVENTS:
+ return "NodeSocketInterfaceEvents";
+ case SOCK_FORCES:
+ return "NodeSocketInterfaceForces";
+ case SOCK_CONTROL_FLOW:
+ return "NodeSocketInterfaceControlFlow";
}
return NULL;
}
@@ -977,6 +1067,9 @@ static void node_socket_free(bNodeTree *UNUSED(ntree),
}
if (sock->default_value) {
+ if (do_id_user) {
+ socket_id_user_decrement(sock);
+ }
MEM_freeN(sock->default_value);
}
}
@@ -1263,6 +1356,10 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
if (sock_src->default_value) {
sock_dst->default_value = MEM_dupallocN(sock_src->default_value);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ socket_id_user_increment(sock_dst);
+ }
}
sock_dst->stack_index = 0;
@@ -2083,6 +2180,13 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
if (node->id) {
id_us_min(node->id);
}
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ socket_id_user_decrement(sock);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ socket_id_user_decrement(sock);
+ }
}
/* Remove animation data. */
@@ -2102,13 +2206,18 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
node_free_node(ntree, node);
}
-static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock)
+static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
+ bNodeSocket *sock,
+ const bool do_id_user)
{
if (sock->prop) {
- IDP_FreeProperty(sock->prop);
+ IDP_FreeProperty_ex(sock->prop, do_id_user);
}
if (sock->default_value) {
+ if (do_id_user) {
+ socket_id_user_decrement(sock);
+ }
MEM_freeN(sock->default_value);
}
}
@@ -2143,7 +2252,7 @@ void ntreeFreeTree(bNodeTree *ntree)
BKE_animdata_free(&ntree->id, false);
}
-void ntreeFreeNestedTree(bNodeTree *ntree)
+void ntreeFreeEmbeddedTree(bNodeTree *ntree)
{
ntreeFreeTree(ntree);
BKE_libblock_free_data(&ntree->id, true);
@@ -2266,6 +2375,8 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id)
return &((Scene *)id)->nodetree;
case ID_LS:
return &((FreestyleLineStyle *)id)->nodetree;
+ case ID_SIM:
+ return &((Simulation *)id)->nodetree;
default:
return NULL;
}
@@ -2529,7 +2640,7 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
BLI_remlink(&ntree->inputs, sock);
BLI_remlink(&ntree->outputs, sock);
- node_socket_interface_free(ntree, sock);
+ node_socket_interface_free(ntree, sock, true);
MEM_freeN(sock);
ntree->update |= NTREE_UPDATE_GROUP;
@@ -4114,6 +4225,33 @@ static void registerTextureNodes(void)
register_node_type_tex_proc_distnoise();
}
+static void registerSimulationNodes(void)
+{
+ register_node_type_sim_group();
+
+ register_node_type_sim_particle_simulation();
+ register_node_type_sim_force();
+ register_node_type_sim_set_particle_attribute();
+ register_node_type_sim_particle_birth_event();
+ register_node_type_sim_particle_time_step_event();
+ register_node_type_sim_execute_condition();
+ register_node_type_sim_multi_execute();
+ register_node_type_sim_particle_mesh_emitter();
+ register_node_type_sim_particle_mesh_collision_event();
+ register_node_type_sim_emit_particles();
+ register_node_type_sim_time();
+ register_node_type_sim_particle_attribute();
+}
+
+static void registerFunctionNodes(void)
+{
+ register_node_type_fn_boolean_math();
+ register_node_type_fn_float_compare();
+ register_node_type_fn_switch();
+ register_node_type_fn_group_instance_id();
+ register_node_type_fn_combine_strings();
+}
+
void init_nodesystem(void)
{
nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh");
@@ -4127,6 +4265,7 @@ void init_nodesystem(void)
register_node_tree_type_cmp();
register_node_tree_type_sh();
register_node_tree_type_tex();
+ register_node_tree_type_sim();
register_node_type_frame();
register_node_type_reroute();
@@ -4136,6 +4275,8 @@ void init_nodesystem(void)
registerCompositNodes();
registerShaderNodes();
registerTextureNodes();
+ registerSimulationNodes();
+ registerFunctionNodes();
}
void free_nodesystem(void)
@@ -4192,6 +4333,7 @@ void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *b
ntreeiter->light = bmain->lights.first;
ntreeiter->world = bmain->worlds.first;
ntreeiter->linestyle = bmain->linestyles.first;
+ ntreeiter->simulation = bmain->simulations.first;
}
bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
bNodeTree **r_nodetree,
@@ -4232,6 +4374,11 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
*r_id = (ID *)ntreeiter->linestyle;
ntreeiter->linestyle = ntreeiter->linestyle->id.next;
}
+ else if (ntreeiter->simulation) {
+ *r_nodetree = ntreeiter->simulation->nodetree;
+ *r_id = (ID *)ntreeiter->simulation;
+ ntreeiter->simulation = ntreeiter->simulation->id.next;
+ }
else {
return false;
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index f68b1a4d314..4df8b6f595a 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -83,6 +83,7 @@
#include "BKE_editmesh.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
@@ -514,21 +515,31 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
mti = modifierType_getInfo(modifier_type);
- /* only geometry objects should be able to get modifiers [#25291] */
- if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
- return false;
+ /* Only geometry objects should be able to get modifiers [#25291] */
+ if (ob->type == OB_HAIR) {
+ return (mti->modifyHair != NULL) || (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
}
-
- if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
- return false;
+ else if (ob->type == OB_POINTCLOUD) {
+ return (mti->modifyPointCloud != NULL) ||
+ (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
+ }
+ else if (ob->type == OB_VOLUME) {
+ return (mti->modifyVolume != NULL);
}
+ else if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly) == 0) {
+ return false;
+ }
- if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
- (ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh)))) {
- return false;
+ if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
+ (ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh)))) {
+ return false;
+ }
+
+ return true;
}
- return true;
+ return false;
}
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
@@ -2677,7 +2688,7 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o
{
/* Execute drivers and animation. */
const bool flush_to_original = DEG_is_active(depsgraph);
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL, flush_to_original);
+ BKE_animsys_evaluate_animdata(&ob->id, ob->adt, ctime, ADT_RECALC_ALL, flush_to_original);
object_where_is_calc_ex(depsgraph, scene, ob, ctime, NULL, NULL);
}
@@ -4567,8 +4578,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* TODO(sergey): What about animation? */
ob->id.recalc |= ID_RECALC_ALL;
if (update_mesh) {
- BKE_animsys_evaluate_animdata(
- scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(&ob->id, ob->adt, frame, ADT_RECALC_ANIM, flush_to_original);
/* ignore cache clear during subframe updates
* to not mess up cache validity */
object_cacheIgnoreClear(ob, 1);
@@ -4582,14 +4592,12 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* for curve following objects, parented curve has to be updated too */
if (ob->type == OB_CURVE) {
Curve *cu = ob->data;
- BKE_animsys_evaluate_animdata(
- scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(&cu->id, cu->adt, frame, ADT_RECALC_ANIM, flush_to_original);
}
/* and armatures... */
if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
- BKE_animsys_evaluate_animdata(
- scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(&arm->id, arm->adt, frame, ADT_RECALC_ANIM, flush_to_original);
BKE_pose_where_is(depsgraph, scene, ob);
}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 2683d384bc7..8957628c76a 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -453,21 +453,17 @@ static void ocean_compute_htilda(void *__restrict userdata,
}
}
-static void ocean_compute_displacement_y(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_displacement_y(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
fftw_execute(o->_disp_y_plan);
}
-static void ocean_compute_displacement_x(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_displacement_x(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float scale = osd->scale;
const float chop_amount = osd->chop_amount;
@@ -494,11 +490,9 @@ static void ocean_compute_displacement_x(TaskPool *__restrict pool,
fftw_execute(o->_disp_x_plan);
}
-static void ocean_compute_displacement_z(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_displacement_z(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float scale = osd->scale;
const float chop_amount = osd->chop_amount;
@@ -525,11 +519,9 @@ static void ocean_compute_displacement_z(TaskPool *__restrict pool,
fftw_execute(o->_disp_z_plan);
}
-static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float chop_amount = osd->chop_amount;
int i, j;
@@ -560,11 +552,9 @@ static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool,
}
}
-static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float chop_amount = osd->chop_amount;
int i, j;
@@ -595,11 +585,9 @@ static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool,
}
}
-static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float chop_amount = osd->chop_amount;
int i, j;
@@ -624,11 +612,9 @@ static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool,
fftw_execute(o->_Jxz_plan);
}
-static void ocean_compute_normal_x(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_normal_x(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
int i, j;
@@ -645,11 +631,9 @@ static void ocean_compute_normal_x(TaskPool *__restrict pool,
fftw_execute(o->_N_x_plan);
}
-static void ocean_compute_normal_z(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_normal_z(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
int i, j;
@@ -668,7 +652,6 @@ static void ocean_compute_normal_z(TaskPool *__restrict pool,
void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount)
{
- TaskScheduler *scheduler = BLI_task_scheduler_get();
TaskPool *pool;
OceanSimulateData osd;
@@ -680,7 +663,7 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount
osd.scale = scale;
osd.chop_amount = chop_amount;
- pool = BLI_task_pool_create(scheduler, &osd, TASK_PRIORITY_HIGH);
+ pool = BLI_task_pool_create(&osd, TASK_PRIORITY_HIGH);
BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 4bbbae7081d..4b90e320052 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1414,7 +1414,7 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
continue;
}
- if (BKE_multires_sculpt_level_get(mmd) > 0) {
+ if (mmd->sculptlvl > 0) {
return mmd;
}
else {
@@ -1686,7 +1686,7 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
* isn't one already */
if (mmd && !CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) {
GridPaintMask *gmask;
- int level = max_ii(1, BKE_multires_sculpt_level_get(mmd));
+ int level = max_ii(1, mmd->sculptlvl);
int gridsize = BKE_ccg_gridsize(level);
int gridarea = gridsize * gridsize;
int i, j;
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 0e35fa5d19f..e5ebae02558 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -2787,9 +2787,7 @@ static void psys_thread_create_path(ParticleTask *task,
}
}
-static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
ParticleTask *task = taskdata;
ParticleThreadContext *ctx = task->ctx;
@@ -2810,7 +2808,6 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
const bool editupdate,
const bool use_render_params)
{
- TaskScheduler *task_scheduler;
TaskPool *task_pool;
ParticleThreadContext ctx;
ParticleTask *tasks_parent, *tasks_child;
@@ -2826,8 +2823,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
return;
}
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &ctx, TASK_PRIORITY_LOW);
+ task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW);
totchild = ctx.totchild;
totparent = ctx.totparent;
@@ -3377,7 +3373,6 @@ void psys_cache_edit_paths(Depsgraph *depsgraph,
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings);
edit->totcached = totpart;
@@ -4009,7 +4004,7 @@ static void get_cpa_texture(Mesh *mesh,
break;
}
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
+ RE_texture_evaluate(mtex, texvec, 0, NULL, false, false, &value, rgba);
if ((event & mtex->mapto) & PAMAP_ROUGH) {
ptex->rough1 = ptex->rough2 = ptex->roughe = texture_value_blend(
@@ -4124,7 +4119,7 @@ void psys_get_texture(
break;
}
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
+ RE_texture_evaluate(mtex, texvec, 0, NULL, false, false, &value, rgba);
if ((event & mtex->mapto) & PAMAP_TIME) {
/* the first time has to set the base value for time regardless of blend mode */
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index d91e27a92d8..7b9b2484dbe 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -773,9 +773,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i
}
}
-static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
ParticleTask *task = taskdata;
ParticleSystem *psys = task->ctx->sim.psys;
@@ -804,9 +802,7 @@ static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool),
}
}
-static void exec_distribute_child(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void exec_distribute_child(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
ParticleTask *task = taskdata;
ParticleSystem *psys = task->ctx->sim.psys;
@@ -1324,7 +1320,6 @@ static void psys_task_init_distribute(ParticleTask *task, ParticleSimulationData
static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
{
- TaskScheduler *task_scheduler;
TaskPool *task_pool;
ParticleThreadContext ctx;
ParticleTask *tasks;
@@ -1336,8 +1331,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
return;
}
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &ctx, TASK_PRIORITY_LOW);
+ task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW);
totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart);
psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks);
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index f7400264131..83f1dca4b8c 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -3693,10 +3693,11 @@ typedef struct DynamicStepSolverTaskData {
SpinLock spin;
} DynamicStepSolverTaskData;
-static void dynamics_step_finalize_sphdata(void *__restrict UNUSED(userdata),
- void *__restrict tls_userdata_chunk)
+static void dynamics_step_sphdata_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict UNUSED(join_v),
+ void *__restrict chunk_v)
{
- SPHData *sphdata = tls_userdata_chunk;
+ SPHData *sphdata = chunk_v;
psys_sph_flush_springs(sphdata);
}
@@ -3987,7 +3988,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
settings.use_threading = (psys->totpart > 100);
settings.userdata_chunk = &sphdata;
settings.userdata_chunk_size = sizeof(sphdata);
- settings.func_finalize = dynamics_step_finalize_sphdata;
+ settings.func_reduce = dynamics_step_sphdata_reduce;
BLI_task_parallel_range(
0, psys->totpart, &task_data, dynamics_step_sph_ddr_task_cb_ex, &settings);
@@ -4019,7 +4020,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
settings.use_threading = (psys->totpart > 100);
settings.userdata_chunk = &sphdata;
settings.userdata_chunk_size = sizeof(sphdata);
- settings.func_finalize = dynamics_step_finalize_sphdata;
+ settings.func_reduce = dynamics_step_sphdata_reduce;
BLI_task_parallel_range(0,
psys->totpart,
&task_data,
@@ -4034,7 +4035,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
settings.use_threading = (psys->totpart > 100);
settings.userdata_chunk = &sphdata;
settings.userdata_chunk_size = sizeof(sphdata);
- settings.func_finalize = dynamics_step_finalize_sphdata;
+ settings.func_reduce = dynamics_step_sphdata_reduce;
BLI_task_parallel_range(0,
psys->totpart,
&task_data,
@@ -4190,7 +4191,7 @@ static void particles_fluid_step(ParticleSimulationData *sim,
ParticleSettings *part = psys->part;
ParticleData *pa = NULL;
- int p, totpart, tottypepart = 0;
+ int p, totpart = 0, tottypepart = 0;
int flagActivePart, activeParts = 0;
float posX, posY, posZ, velX, velY, velZ;
float resX, resY, resZ;
@@ -4848,7 +4849,7 @@ void particle_system_update(struct Depsgraph *depsgraph,
hcfra = 100.0f * (float)i / (float)psys->part->hair_step;
if ((part->flag & PART_HAIR_REGROW) == 0) {
BKE_animsys_evaluate_animdata(
- scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false);
+ &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false);
}
system_step(&sim, hcfra, use_render_params);
psys->cfra = hcfra;
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index e6d672ad9d9..aa541b3d715 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -1115,11 +1115,11 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode)
.vnors = vnors,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
MEM_freeN(vnors);
}
@@ -1169,9 +1169,9 @@ static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, in
.flag = flag,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings);
}
static void pbvh_update_visibility_redraw_task_cb(void *__restrict userdata,
@@ -1207,9 +1207,9 @@ static void pbvh_update_visibility_redraw(PBVH *bvh, PBVHNode **nodes, int totno
.flag = flag,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_visibility_redraw_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_visibility_redraw_task_cb, &settings);
}
static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata,
@@ -1245,9 +1245,9 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
.flag = flag,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
}
static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol)
@@ -1365,9 +1365,9 @@ static void pbvh_update_draw_buffers(
.show_vcol = show_vcol,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings);
}
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
@@ -1558,9 +1558,9 @@ static void pbvh_update_visibility(PBVH *bvh, PBVHNode **nodes, int totnode)
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_visibility_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_visibility_task_cb, &settings);
}
void BKE_pbvh_update_visibility(PBVH *bvh)
@@ -2994,7 +2994,7 @@ void BKE_pbvh_get_frustum_planes(PBVH *bvh, PBVHFrustumPlanes *planes)
}
}
-void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings,
+void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings,
bool use_threading,
int totnode)
{
diff --git a/source/blender/blenkernel/intern/pointcloud.c b/source/blender/blenkernel/intern/pointcloud.c
index 31b8de53291..c943d30aaa5 100644
--- a/source/blender/blenkernel/intern/pointcloud.c
+++ b/source/blender/blenkernel/intern/pointcloud.c
@@ -184,7 +184,7 @@ void BKE_pointcloud_update_customdata_pointers(PointCloud *pointcloud)
PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int totpoint)
{
- PointCloud *pointcloud_dst = BKE_id_new_nomain(ID_HA, NULL);
+ PointCloud *pointcloud_dst = BKE_id_new_nomain(ID_PT, NULL);
STRNCPY(pointcloud_dst->id.name, pointcloud_src->id.name);
pointcloud_dst->mat = MEM_dupallocN(pointcloud_src->mat);
@@ -211,12 +211,65 @@ PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool
return result;
}
-static PointCloud *pointcloud_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph),
- struct Scene *UNUSED(scene),
- Object *UNUSED(object),
+static PointCloud *pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
PointCloud *pointcloud_input)
{
- return pointcloud_input;
+ PointCloud *pointcloud = pointcloud_input;
+
+ /* Modifier evaluation modes. */
+ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
+ const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(object, &virtualModifierData);
+
+ /* Evaluate modifiers. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if ((mti->type == eModifierTypeType_OnlyDeform) &&
+ (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
+ /* Ensure we are not modifying the input. */
+ if (pointcloud == pointcloud_input) {
+ pointcloud = BKE_pointcloud_copy_for_eval(pointcloud, true);
+ }
+
+ /* Ensure we are not overwriting referenced data. */
+ CustomData_duplicate_referenced_layer(&pointcloud->pdata, CD_LOCATION, pointcloud->totpoint);
+ BKE_pointcloud_update_customdata_pointers(pointcloud);
+
+ /* Created deformed coordinates array on demand. */
+ mti->deformVerts(md, &mectx, NULL, pointcloud->co, pointcloud->totpoint);
+ }
+ else if (mti->modifyPointCloud) {
+ /* Ensure we are not modifying the input. */
+ if (pointcloud == pointcloud_input) {
+ pointcloud = BKE_pointcloud_copy_for_eval(pointcloud, true);
+ }
+
+ PointCloud *pointcloud_next = mti->modifyPointCloud(md, &mectx, pointcloud);
+
+ if (pointcloud_next && pointcloud_next != pointcloud) {
+ /* If the modifier returned a new pointcloud, release the old one. */
+ if (pointcloud != pointcloud_input) {
+ BKE_id_free(NULL, pointcloud);
+ }
+ pointcloud = pointcloud_next;
+ }
+ }
+ }
+
+ return pointcloud;
}
void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index f7c018edbd8..5a6d729568a 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -340,7 +340,7 @@ static void scene_free_data(ID *id)
/* is no lib link block, but scene extension */
if (scene->nodetree) {
- ntreeFreeNestedTree(scene->nodetree);
+ ntreeFreeEmbeddedTree(scene->nodetree);
MEM_freeN(scene->nodetree);
scene->nodetree = NULL;
}
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index c1644e39afa..9fa43ed0a5f 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -61,6 +61,8 @@
#include "BLF_api.h"
+static struct SeqEffectHandle get_sequence_effect_impl(int seq_type);
+
static void slice_get_byte_buffers(const SeqRenderData *context,
const ImBuf *ibuf1,
const ImBuf *ibuf2,
@@ -3118,7 +3120,7 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla
static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
{
- return EARLY_USE_INPUT_1;
+ return EARLY_DO_EFFECT;
}
static void store_icu_yrange_speed(Sequence *seq, short UNUSED(adrcode), float *ymin, float *ymax)
@@ -3248,36 +3250,60 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for
}
}
+/* Override cfra when rendering speed effect input. */
+float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ int input)
+{
+ int nr = BKE_sequencer_give_stripelem_index(seq, cfra);
+ SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
+ BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false);
+
+ /* No interpolation. */
+ if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) {
+ return seq->start + s->frameMap[nr];
+ }
+
+ /* We need to provide current and next image for interpolation. */
+ if (input == 0) { /* Current frame. */
+ return floor(seq->start + s->frameMap[nr]);
+ }
+ else { /* Next frame. */
+ return ceil(seq->start + s->frameMap[nr]);
+ }
+}
+
+static float speed_effect_interpolation_ratio_get(SpeedControlVars *s, Sequence *seq, float cfra)
+{
+ int nr = BKE_sequencer_give_stripelem_index(seq, cfra);
+ return s->frameMap[nr] - floor(s->frameMap[nr]);
+}
+
static ImBuf *do_speed_effect(const SeqRenderData *context,
- Sequence *UNUSED(seq),
- float UNUSED(cfra),
+ Sequence *seq,
+ float cfra,
float facf0,
float facf1,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+ SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
+ struct SeqEffectHandle cross_effect = get_sequence_effect_impl(SEQ_TYPE_CROSS);
+ ImBuf *out;
- if (out->rect_float) {
- do_cross_effect_float(facf0,
- facf1,
- context->rectx,
- context->recty,
- ibuf1->rect_float,
- ibuf2->rect_float,
- out->rect_float);
+ if (s->flags & SEQ_SPEED_USE_INTERPOLATION) {
+ out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+ facf0 = facf1 = speed_effect_interpolation_ratio_get(s, seq, cfra);
+ /* Current frame is ibuf1, next frame is ibuf2. */
+ out = BKE_sequencer_effect_execute_threaded(
+ &cross_effect, context, NULL, cfra, facf0, facf1, ibuf1, ibuf2, ibuf3);
+ return out;
}
- else {
- do_cross_effect_byte(facf0,
- facf1,
- context->rectx,
- context->recty,
- (unsigned char *)ibuf1->rect,
- (unsigned char *)ibuf2->rect,
- (unsigned char *)out->rect);
- }
- return out;
+
+ /* No interpolation. */
+ return IMB_dupImBuf(ibuf1);
}
/*********************** overdrop *************************/
diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c
index dabfd26f5b0..1425bff48a8 100644
--- a/source/blender/blenkernel/intern/seqprefetch.c
+++ b/source/blender/blenkernel/intern/seqprefetch.c
@@ -343,8 +343,7 @@ static void *seq_prefetch_frames(void *job)
seq_prefetch_update_depsgraph(pfjob);
AnimData *adt = BKE_animdata_from_id(&pfjob->context_cpy.scene->id);
- BKE_animsys_evaluate_animdata(pfjob->context_cpy.scene,
- &pfjob->context_cpy.scene->id,
+ BKE_animsys_evaluate_animdata(&pfjob->context_cpy.scene->id,
adt,
pfjob->cfra + pfjob->num_frames_prefetched,
ADT_RECALC_ALL,
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index d3d885fccd9..b962c99b109 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -1394,7 +1394,7 @@ static void multibuf(ImBuf *ibuf, const float fmul)
}
}
-static float give_stripelem_index(Sequence *seq, float cfra)
+float BKE_sequencer_give_stripelem_index(Sequence *seq, float cfra)
{
float nr;
int sta = seq->start;
@@ -1452,7 +1452,7 @@ StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra)
* all other strips don't use this...
*/
- int nr = (int)give_stripelem_index(seq, cfra);
+ int nr = (int)BKE_sequencer_give_stripelem_index(seq, cfra);
if (nr == -1 || se == NULL) {
return NULL;
@@ -1889,7 +1889,7 @@ static bool seq_proxy_get_fname(Editing *ed,
frameno = 1;
}
else {
- frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
+ frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs;
BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, proxy_size_number, suffix);
}
@@ -1922,7 +1922,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
}
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
- int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
+ int frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs;
if (proxy->anim == NULL) {
if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) {
return NULL;
@@ -2887,15 +2887,15 @@ static void *render_effect_execute_do_thread(void *thread_data_v)
return NULL;
}
-static ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
- const SeqRenderData *context,
- Sequence *seq,
- float cfra,
- float facf0,
- float facf1,
- ImBuf *ibuf1,
- ImBuf *ibuf2,
- ImBuf *ibuf3)
+ImBuf *BKE_sequencer_effect_execute_threaded(struct SeqEffectHandle *sh,
+ const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
{
RenderEffectInitData init_data;
ImBuf *out = sh->init_execution(context, ibuf1, ibuf2, ibuf3);
@@ -2969,14 +2969,21 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
break;
case EARLY_DO_EFFECT:
for (i = 0; i < 3; i++) {
- if (input[i]) {
- ibuf[i] = seq_render_strip(context, state, input[i], cfra);
+ /* Speed effect requires time remapping of cfra for input(s). */
+ if (input[1] && seq->type == SEQ_TYPE_SPEED) {
+ float target_frame = BKE_sequencer_speed_effect_target_frame_get(context, seq, cfra, i);
+ ibuf[i] = seq_render_strip(context, state, input[i], target_frame);
+ }
+ else { /* Other effects. */
+ if (input[i]) {
+ ibuf[i] = seq_render_strip(context, state, input[i], cfra);
+ }
}
}
if (ibuf[0] && ibuf[1]) {
if (sh.multithreaded) {
- out = seq_render_effect_execute_threaded(
+ out = BKE_sequencer_effect_execute_threaded(
&sh, context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
}
else {
@@ -3330,8 +3337,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
/* anim-data */
adt = BKE_animdata_from_id(&mask->id);
- BKE_animsys_evaluate_animdata(
- context->scene, &mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(&mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false);
maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
@@ -3660,8 +3666,7 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
if (seqbase && !BLI_listbase_is_empty(seqbase)) {
if (seq->flag & SEQ_SCENE_STRIPS && seq->scene) {
- BKE_animsys_evaluate_all_animation(
- context->bmain, context->depsgraph, seq->scene, nr + offset);
+ BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, nr + offset);
}
ibuf = seq_render_strip_stack(context,
@@ -3681,9 +3686,8 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
float cfra)
{
ImBuf *ibuf = NULL;
- float nr = give_stripelem_index(seq, cfra);
- int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT :
- seq->type;
+ float nr = BKE_sequencer_give_stripelem_index(seq, cfra);
+ int type = (seq->type & SEQ_TYPE_EFFECT) ? SEQ_TYPE_EFFECT : seq->type;
switch (type) {
case SEQ_TYPE_META: {
ibuf = do_render_strip_seqbase(context, state, seq, nr);
@@ -3725,21 +3729,8 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
break;
}
- case SEQ_TYPE_SPEED: {
- float f_cfra;
- SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
-
- BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false);
-
- /* weeek! */
- f_cfra = seq->start + s->frameMap[(int)nr];
- ibuf = seq_render_strip(context, state, seq->seq1, f_cfra);
-
- break;
- }
-
case SEQ_TYPE_EFFECT: {
- ibuf = seq_render_effect_strip_impl(context, state, seq, seq->start + nr);
+ ibuf = seq_render_effect_strip_impl(context, state, seq, cfra);
break;
}
@@ -3933,7 +3924,7 @@ static ImBuf *seq_render_strip_stack_apply_effect(
if (swap_input) {
if (sh.multithreaded) {
- out = seq_render_effect_execute_threaded(
+ out = BKE_sequencer_effect_execute_threaded(
&sh, context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL);
}
else {
@@ -3942,7 +3933,7 @@ static ImBuf *seq_render_strip_stack_apply_effect(
}
else {
if (sh.multithreaded) {
- out = seq_render_effect_execute_threaded(
+ out = BKE_sequencer_effect_execute_threaded(
&sh, context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL);
}
else {
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
new file mode 100644
index 00000000000..ace91424764
--- /dev/null
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -0,0 +1,110 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_defaults.h"
+#include "DNA_simulation_types.h"
+
+#include "BLI_compiler_compat.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_anim_data.h"
+#include "BKE_animsys.h"
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
+#include "BKE_lib_remap.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_simulation.h"
+
+#include "NOD_simulation.h"
+
+#include "BLT_translation.h"
+
+static void simulation_init_data(ID *id)
+{
+ Simulation *simulation = (Simulation *)id;
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(simulation, id));
+
+ MEMCPY_STRUCT_AFTER(simulation, DNA_struct_default_get(Simulation), id);
+
+ bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname);
+ simulation->nodetree = ntree;
+}
+
+static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
+{
+ Simulation *simulation_dst = (Simulation *)id_dst;
+ Simulation *simulation_src = (Simulation *)id_src;
+
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
+ if (simulation_src->nodetree) {
+ BKE_id_copy_ex(bmain,
+ (ID *)simulation_src->nodetree,
+ (ID **)&simulation_dst->nodetree,
+ flag_private_id_data);
+ }
+}
+
+static void simulation_free_data(ID *id)
+{
+ Simulation *simulation = (Simulation *)id;
+
+ BKE_animdata_free(&simulation->id, false);
+
+ if (simulation->nodetree) {
+ ntreeFreeEmbeddedTree(simulation->nodetree);
+ MEM_freeN(simulation->nodetree);
+ simulation->nodetree = nullptr;
+ }
+}
+
+void *BKE_simulation_add(Main *bmain, const char *name)
+{
+ Simulation *simulation = (Simulation *)BKE_libblock_alloc(bmain, ID_SIM, name, 0);
+
+ simulation_init_data(&simulation->id);
+
+ return simulation;
+}
+
+IDTypeInfo IDType_ID_SIM = {
+ /* id_code */ ID_SIM,
+ /* id_filter */ FILTER_ID_SIM,
+ /* main_listbase_index */ INDEX_ID_SIM,
+ /* struct_size */ sizeof(Simulation),
+ /* name */ "Simulation",
+ /* name_plural */ "simulations",
+ /* translation_context */ BLT_I18NCONTEXT_ID_SIMULATION,
+ /* flags */ 0,
+
+ /* init_data */ simulation_init_data,
+ /* copy_data */ simulation_copy_data,
+ /* free_data */ simulation_free_data,
+ /* make_local */ nullptr,
+};
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 64fe396d6a3..5500918428f 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -751,12 +751,12 @@ static void sound_start_play_scene(Scene *scene)
}
}
-static float get_cur_time(Scene *scene)
+static double get_cur_time(Scene *scene)
{
/* We divide by the current framelen to take into account time remapping.
* Otherwise we will get the wrong starting time which will break A/V sync.
* See T74111 for further details. */
- return FRA2TIME((CFRA + SUBFRA) / scene->r.framelen);
+ return FRA2TIME((CFRA + SUBFRA) / (double)scene->r.framelen);
}
void BKE_sound_play_scene(Scene *scene)
@@ -764,7 +764,7 @@ void BKE_sound_play_scene(Scene *scene)
sound_verify_evaluated_id(&scene->id);
AUD_Status status;
- const float cur_time = get_cur_time(scene);
+ const double cur_time = get_cur_time(scene);
AUD_Device_lock(sound_device);
@@ -811,8 +811,8 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene)
bScreen *screen;
int animation_playing;
- const float one_frame = (float)(1.0 / FPS);
- const float cur_time = FRA2TIME(CFRA);
+ const double one_frame = 1.0 / FPS;
+ const double cur_time = FRA2TIME(CFRA);
AUD_Device_lock(sound_device);
@@ -869,7 +869,7 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene)
AUD_Device_unlock(sound_device);
}
-float BKE_sound_sync_scene(Scene *scene)
+double BKE_sound_sync_scene(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
@@ -1230,7 +1230,7 @@ void BKE_sound_stop_scene(Scene *UNUSED(scene))
void BKE_sound_seek_scene(Main *UNUSED(bmain), Scene *UNUSED(scene))
{
}
-float BKE_sound_sync_scene(Scene *UNUSED(scene))
+double BKE_sound_sync_scene(Scene *UNUSED(scene))
{
return NAN_FLT;
}
@@ -1341,7 +1341,7 @@ void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback)
#endif
}
-void BKE_sound_jack_scene_update(Scene *scene, int mode, float time)
+void BKE_sound_jack_scene_update(Scene *scene, int mode, double time)
{
sound_verify_evaluated_id(&scene->id);
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index 0ae32701cd5..d5d5530c1ce 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -40,9 +40,9 @@
#include "opensubdiv_topology_refiner_capi.h"
-/* =============================================================================
- * Various forward declarations.
- */
+/* -------------------------------------------------------------------- */
+/** \name Various forward declarations
+ * \{ */
static void subdiv_ccg_average_all_boundaries_and_corners(SubdivCCG *subdiv_ccg, CCGKey *key);
@@ -50,9 +50,11 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG *subdiv_ccg,
CCGKey *key,
SubdivCCGFace *face);
-/* =============================================================================
- * Generally useful internal helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generally useful internal helpers
+ * \{ */
/* Number of floats in per-vertex elements. */
static int num_element_float_get(const SubdivCCG *subdiv_ccg)
@@ -74,9 +76,11 @@ static int element_size_bytes_get(const SubdivCCG *subdiv_ccg)
return sizeof(float) * num_element_float_get(subdiv_ccg);
}
-/* =============================================================================
- * Internal helpers for CCG creation.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal helpers for CCG creation
+ * \{ */
static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg, const SubdivToCCGSettings *settings)
{
@@ -158,9 +162,11 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv)
}
}
-/* =============================================================================
- * Grids evaluation.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Grids evaluation
+ * \{ */
typedef struct CCGEvalGridsData {
SubdivCCG *subdiv_ccg;
@@ -556,9 +562,11 @@ static void subdiv_ccg_init_faces_neighborhood(SubdivCCG *subdiv_ccg)
subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg);
}
-/* =============================================================================
- * Creation / evaluation.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Creation / evaluation
+ * \{ */
SubdivCCG *BKE_subdiv_to_ccg(Subdiv *subdiv,
const SubdivToCCGSettings *settings,
@@ -670,9 +678,11 @@ void BKE_subdiv_ccg_key_top_level(CCGKey *key, const SubdivCCG *subdiv_ccg)
BKE_subdiv_ccg_key(key, subdiv_ccg, subdiv_ccg->level);
}
-/* =============================================================================
- * Normals.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Normals
+ * \{ */
typedef struct RecalcInnerNormalsData {
SubdivCCG *subdiv_ccg;
@@ -770,8 +780,8 @@ static void subdiv_ccg_recalc_inner_normal_task(void *__restrict userdata_v,
subdiv_ccg_average_inner_face_normals(data->subdiv_ccg, data->key, tls, grid_index);
}
-static void subdiv_ccg_recalc_inner_normal_finalize(void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_recalc_inner_normal_free(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
RecalcInnerNormalsTLSData *tls = tls_v;
MEM_SAFE_FREE(tls->face_normals);
@@ -791,7 +801,7 @@ static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG *subdiv_ccg)
BLI_parallel_range_settings_defaults(&parallel_range_settings);
parallel_range_settings.userdata_chunk = &tls_data;
parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize = subdiv_ccg_recalc_inner_normal_finalize;
+ parallel_range_settings.func_free = subdiv_ccg_recalc_inner_normal_free;
BLI_task_parallel_range(0,
subdiv_ccg->num_grids,
&data,
@@ -834,8 +844,8 @@ static void subdiv_ccg_recalc_modified_inner_normal_task(void *__restrict userda
subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
}
-static void subdiv_ccg_recalc_modified_inner_normal_finalize(void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_recalc_modified_inner_normal_free(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
RecalcInnerNormalsTLSData *tls = tls_v;
MEM_SAFE_FREE(tls->face_normals);
@@ -857,7 +867,7 @@ static void subdiv_ccg_recalc_modified_inner_grid_normals(SubdivCCG *subdiv_ccg,
BLI_parallel_range_settings_defaults(&parallel_range_settings);
parallel_range_settings.userdata_chunk = &tls_data;
parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize = subdiv_ccg_recalc_modified_inner_normal_finalize;
+ parallel_range_settings.func_free = subdiv_ccg_recalc_modified_inner_normal_free;
BLI_task_parallel_range(0,
num_effected_faces,
&data,
@@ -885,9 +895,11 @@ void BKE_subdiv_ccg_update_normals(SubdivCCG *subdiv_ccg,
subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
}
-/* =============================================================================
- * Boundary averaging/stitching.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Boundary averaging/stitching
+ * \{ */
typedef struct AverageInnerGridsData {
SubdivCCG *subdiv_ccg;
@@ -1077,8 +1089,8 @@ static void subdiv_ccg_average_grids_boundaries_task(void *__restrict userdata_v
subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, tls);
}
-static void subdiv_ccg_average_grids_boundaries_finalize(void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_average_grids_boundaries_free(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
AverageGridsBoundariesTLSData *tls = tls_v;
MEM_SAFE_FREE(tls->accumulators);
@@ -1136,7 +1148,7 @@ static void subdiv_ccg_average_all_boundaries(SubdivCCG *subdiv_ccg, CCGKey *key
AverageGridsBoundariesTLSData tls_data = {NULL};
parallel_range_settings.userdata_chunk = &tls_data;
parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize = subdiv_ccg_average_grids_boundaries_finalize;
+ parallel_range_settings.func_free = subdiv_ccg_average_grids_boundaries_free;
BLI_task_parallel_range(0,
subdiv_ccg->num_adjacent_edges,
&boundaries_data,
@@ -1244,9 +1256,11 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg,
*r_num_loops = *r_num_faces * 4;
}
-/* =============================================================================
- * Neighbors.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Neighbors
+ * \{ */
void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord)
{
@@ -1791,3 +1805,5 @@ int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int gri
const int face_index = face - subdiv_ccg->faces;
return face_index;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c
index db0a51c390b..f03cf4c4d21 100644
--- a/source/blender/blenkernel/intern/subdiv_deform.c
+++ b/source/blender/blenkernel/intern/subdiv_deform.c
@@ -39,9 +39,9 @@
#include "MEM_guardedalloc.h"
-/* ================================================================================================
- * Subdivision context.
- */
+/* -------------------------------------------------------------------- */
+/** \name Subdivision context
+ * \{ */
typedef struct SubdivDeformContext {
const Mesh *coarse_mesh;
@@ -77,9 +77,11 @@ static void subdiv_mesh_context_free(SubdivDeformContext *ctx)
MEM_SAFE_FREE(ctx->accumulated_counters);
}
-/* ================================================================================================
- * Accumulation helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Accumulation helpers
+ * \{ */
static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx,
const int ptex_face_index,
@@ -105,9 +107,11 @@ static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx,
++ctx->accumulated_counters[vertex_index];
}
-/* ================================================================================================
- * Subdivision callbacks.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Subdivision callbacks
+ * \{ */
static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context,
const int UNUSED(num_vertices),
@@ -165,9 +169,11 @@ static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_contex
add_v3_v3(vertex_co, D);
}
-/* ================================================================================================
- * Initialization.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Initialization
+ * \{ */
static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
SubdivForeachContext *foreach_context)
@@ -182,9 +188,11 @@ static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
}
-/* ================================================================================================
- * Public entry point.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public entry point
+ * \{ */
void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
const struct Mesh *coarse_mesh,
@@ -234,3 +242,5 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
/* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c
index b31fb2c9312..ff7f6fad5f0 100644
--- a/source/blender/blenkernel/intern/subdiv_foreach.c
+++ b/source/blender/blenkernel/intern/subdiv_foreach.c
@@ -40,9 +40,9 @@
#include "MEM_guardedalloc.h"
-/* =============================================================================
- * General helpers.
- */
+/* -------------------------------------------------------------------- */
+/** \name General helpers
+ * \{ */
/* Number of ptex faces for a given polygon. */
BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly)
@@ -75,9 +75,11 @@ BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution)
return (poly->totloop == 4) ? (resolution) : ((resolution >> 1) + 1);
}
-/* =============================================================================
- * Context which is passed to all threaded tasks.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Context which is passed to all threaded tasks
+ * \{ */
typedef struct SubdivForeachTaskContext {
const Mesh *coarse_mesh;
@@ -122,9 +124,11 @@ typedef struct SubdivForeachTaskContext {
BLI_bitmap *coarse_edges_used_map;
} SubdivForeachTaskContext;
-/* =============================================================================
- * Threading helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Threading helpers
+ * \{ */
static void *subdiv_foreach_tls_alloc(SubdivForeachTaskContext *ctx)
{
@@ -148,9 +152,11 @@ static void subdiv_foreach_tls_free(SubdivForeachTaskContext *ctx, void *tls)
MEM_freeN(tls);
}
-/* =============================================================================
- * Initialization.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Initialization
+ * \{ */
/* NOTE: Expects edge map to be zeroed. */
static void subdiv_foreach_ctx_count(SubdivForeachTaskContext *ctx)
@@ -294,9 +300,11 @@ static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx)
MEM_freeN(ctx->subdiv_polygon_offset);
}
-/* =============================================================================
- * Vertex traversal process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex traversal process
+ * \{ */
/* Traversal of corner vertices. They are coming from coarse vertices. */
@@ -706,9 +714,11 @@ static void subdiv_foreach_vertices(SubdivForeachTaskContext *ctx, void *tls, co
}
}
-/* =============================================================================
- * Edge traversal process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edge traversal process
+ * \{ */
/* TODO(sergey): Coarse edge are always NONE, consider getting rid of it. */
static int subdiv_foreach_edges_row(SubdivForeachTaskContext *ctx,
@@ -1022,9 +1032,11 @@ static void subdiv_foreach_boundary_edges(SubdivForeachTaskContext *ctx,
ctx->foreach_context, tls, coarse_edge_index, subdiv_edge_index, v1, v2);
}
-/* =============================================================================
- * Loops traversal.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loops traversal
+ * \{ */
static void rotate_indices(const int rot, int *a, int *b, int *c, int *d)
{
@@ -1666,9 +1678,11 @@ static void subdiv_foreach_loops(SubdivForeachTaskContext *ctx, void *tls, int p
}
}
-/* =============================================================================
- * Polygons traverse process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Polygons traverse process
+ * \{ */
static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, void *tls, int poly_index)
{
@@ -1697,9 +1711,11 @@ static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, void *tls, int p
}
}
-/* =============================================================================
- * Loose elements traverse process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loose elements traverse process
+ * \{ */
static void subdiv_foreach_loose_vertices_task(void *__restrict userdata,
const int coarse_vertex_index,
@@ -1754,9 +1770,11 @@ static void subdiv_foreach_vertices_of_loose_edges_task(void *__restrict userdat
}
}
-/* =============================================================================
- * Subdivision process entry points.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Subdivision process entry points
+ * \{ */
static void subdiv_foreach_single_geometry_vertices(SubdivForeachTaskContext *ctx, void *tls)
{
@@ -1838,9 +1856,9 @@ static void subdiv_foreach_boundary_edges_task(void *__restrict userdata,
subdiv_foreach_boundary_edges(ctx, tls->userdata_chunk, edge_index);
}
-static void subdiv_foreach_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void subdiv_foreach_free(const void *__restrict userdata, void *__restrict userdata_chunk)
{
- SubdivForeachTaskContext *ctx = userdata;
+ const SubdivForeachTaskContext *ctx = userdata;
ctx->foreach_context->user_data_tls_free(userdata_chunk);
}
@@ -1873,7 +1891,7 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
parallel_range_settings.userdata_chunk_size = context->user_data_tls_size;
parallel_range_settings.min_iter_per_thread = 1;
if (context->user_data_tls_free != NULL) {
- parallel_range_settings.func_finalize = subdiv_foreach_finalize;
+ parallel_range_settings.func_free = subdiv_foreach_free;
}
/* TODO(sergey): Possible optimization is to have a single pool and push all
@@ -1908,3 +1926,5 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
subdiv_foreach_ctx_free(&ctx);
return true;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index bd091108b11..987cc0311c7 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -41,9 +41,9 @@
#include "MEM_guardedalloc.h"
-/* =============================================================================
- * Subdivision context.
- */
+/* -------------------------------------------------------------------- */
+/** \name Subdivision Context
+ * \{ */
typedef struct SubdivMeshContext {
const SubdivToMeshSettings *settings;
@@ -119,9 +119,11 @@ static void subdiv_mesh_context_free(SubdivMeshContext *ctx)
MEM_SAFE_FREE(ctx->accumulated_counters);
}
-/* =============================================================================
- * Loop custom data copy helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop custom data copy helpers
+ * \{ */
typedef struct LoopsOfPtex {
/* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */
@@ -159,9 +161,11 @@ static void loops_of_ptex_get(const SubdivMeshContext *ctx,
}
}
-/* =============================================================================
- * Vertex custom data interpolation helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex custom data interpolation helpers
+ * \{ */
/* TODO(sergey): Somehow de-duplicate with loops storage, without too much
* exception cases all over the code. */
@@ -295,9 +299,11 @@ static void vertex_interpolation_end(VerticesForInterpolation *vertex_interpolat
}
}
-/* =============================================================================
- * Loop custom data interpolation helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop custom data interpolation helpers
+ * \{ */
typedef struct LoopsForInterpolation {
/* This field points to a loop data which is to be used for interpolation.
@@ -413,9 +419,11 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
}
}
-/* =============================================================================
- * TLS.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name TLS
+ * \{ */
typedef struct SubdivMeshTLS {
bool vertex_interpolation_initialized;
@@ -440,9 +448,11 @@ static void subdiv_mesh_tls_free(void *tls_v)
}
}
-/* =============================================================================
- * Evaluation helper functions.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation helper functions
+ * \{ */
static void eval_final_point_and_vertex_normal(Subdiv *subdiv,
const int ptex_face_index,
@@ -459,9 +469,11 @@ static void eval_final_point_and_vertex_normal(Subdiv *subdiv,
}
}
-/* =============================================================================
- * Accumulation helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Accumulation helpers
+ * \{ */
static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *ctx,
const int ptex_face_index,
@@ -490,9 +502,11 @@ static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *
++ctx->accumulated_counters[subdiv_vertex_index];
}
-/* =============================================================================
- * Callbacks.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks
+ * \{ */
static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context,
const int num_vertices,
@@ -513,9 +527,11 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
return true;
}
-/* =============================================================================
- * Vertex subdivision process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex subdivision process
+ * \{ */
static void subdiv_vertex_data_copy(const SubdivMeshContext *ctx,
const MVert *coarse_vertex,
@@ -778,9 +794,11 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context
subdiv_mesh_tag_center_vertex(coarse_poly, subdiv_vert, u, v);
}
-/* =============================================================================
- * Edge subdivision process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edge subdivision process
+ * \{ */
static void subdiv_copy_edge_data(SubdivMeshContext *ctx,
MEdge *subdiv_edge,
@@ -827,9 +845,11 @@ static void subdiv_mesh_edge(const SubdivForeachContext *foreach_context,
subdiv_edge->v2 = subdiv_v2;
}
-/* =============================================================================
- * Loops creation/interpolation.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loops creation/interpolation
+ * \{ */
static void subdiv_interpolate_loop_data(const SubdivMeshContext *ctx,
MLoop *subdiv_loop,
@@ -921,9 +941,11 @@ static void subdiv_mesh_loop(const SubdivForeachContext *foreach_context,
subdiv_loop->e = subdiv_edge_index;
}
-/* =============================================================================
- * Polygons subdivision process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Polygons subdivision process
+ * \{ */
static void subdiv_copy_poly_data(const SubdivMeshContext *ctx,
MPoly *subdiv_poly,
@@ -955,9 +977,11 @@ static void subdiv_mesh_poly(const SubdivForeachContext *foreach_context,
subdiv_poly->totloop = num_loops;
}
-/* =============================================================================
- * Loose elements subdivision process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loose elements subdivision process
+ * \{ */
static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context,
void *UNUSED(tls),
@@ -1127,9 +1151,11 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
normal_float_to_short_v3(subdiv_vertex->no, no);
}
-/* =============================================================================
- * Initialization.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Initialization
+ * \{ */
static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
SubdivForeachContext *foreach_context)
@@ -1157,9 +1183,11 @@ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
foreach_context->user_data_tls_free = subdiv_mesh_tls_free;
}
-/* =============================================================================
- * Public entry point.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public entry point
+ * \{ */
Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
const SubdivToMeshSettings *settings,
@@ -1206,3 +1234,5 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
subdiv_mesh_context_free(&subdiv_context);
return result;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index fe10861f96e..0abee335036 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -112,7 +112,7 @@ static void texture_free_data(ID *id)
/* is no lib link block, but texture extension */
if (texture->nodetree) {
- ntreeFreeNestedTree(texture->nodetree);
+ ntreeFreeEmbeddedTree(texture->nodetree);
MEM_freeN(texture->nodetree);
texture->nodetree = NULL;
}
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 0204667b3bd..97d95cb7e46 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -2288,13 +2288,15 @@ void BKE_tracking_distortion_free(MovieDistortion *distortion)
MEM_freeN(distortion);
}
-void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r_co[2])
+void BKE_tracking_distort_v2(
+ MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2])
{
const MovieTrackingCamera *camera = &tracking->camera;
const float aspy = 1.0f / tracking->camera.pixel_aspect;
libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- tracking_cameraIntrinscisOptionsFromTracking(tracking, 0, 0, &camera_intrinsics_options);
+ tracking_cameraIntrinscisOptionsFromTracking(
+ tracking, image_width, image_height, &camera_intrinsics_options);
libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
/* Normalize coordinates. */
@@ -2309,13 +2311,15 @@ void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r
r_co[1] = y;
}
-void BKE_tracking_undistort_v2(MovieTracking *tracking, const float co[2], float r_co[2])
+void BKE_tracking_undistort_v2(
+ MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2])
{
const MovieTrackingCamera *camera = &tracking->camera;
const float aspy = 1.0f / tracking->camera.pixel_aspect;
libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- tracking_cameraIntrinscisOptionsFromTracking(tracking, 0, 0, &camera_intrinsics_options);
+ tracking_cameraIntrinscisOptionsFromTracking(
+ tracking, image_width, image_height, &camera_intrinsics_options);
libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
double x = co[0], y = co[1];
@@ -2361,13 +2365,19 @@ ImBuf *BKE_tracking_distort_frame(MovieTracking *tracking,
}
void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
+ int image_width,
+ int image_height,
rcti *rect,
bool undistort,
float delta[2])
{
float pos[2], warped_pos[2];
const int coord_delta = 5;
- void (*apply_distortion)(MovieTracking * tracking, const float pos[2], float out[2]);
+ void (*apply_distortion)(MovieTracking * tracking,
+ int image_width,
+ int image_height,
+ const float pos[2],
+ float out[2]);
if (undistort) {
apply_distortion = BKE_tracking_undistort_v2;
@@ -2387,7 +2397,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = a;
pos[1] = rect->ymin;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -2396,7 +2406,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = a;
pos[1] = rect->ymax;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -2415,7 +2425,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = rect->xmin;
pos[1] = a;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -2424,7 +2434,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = rect->xmax;
pos[1] = a;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 5f7452e4775..629c01ec298 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -451,6 +451,12 @@ static void distortion_model_parameters_from_tracking(
camera_intrinsics_options->division_k1 = camera->division_k1;
camera_intrinsics_options->division_k2 = camera->division_k2;
return;
+
+ case TRACKING_DISTORTION_MODEL_NUKE:
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_NUKE;
+ camera_intrinsics_options->nuke_k1 = camera->nuke_k1;
+ camera_intrinsics_options->nuke_k2 = camera->nuke_k2;
+ return;
}
/* Unknown distortion model, which might be due to opening newer file in older Blender.
@@ -479,6 +485,12 @@ static void distortion_model_parameters_from_options(
camera->division_k1 = camera_intrinsics_options->division_k1;
camera->division_k2 = camera_intrinsics_options->division_k2;
return;
+
+ case LIBMV_DISTORTION_MODEL_NUKE:
+ camera->distortion_model = TRACKING_DISTORTION_MODEL_NUKE;
+ camera->nuke_k1 = camera_intrinsics_options->nuke_k1;
+ camera->nuke_k2 = camera_intrinsics_options->nuke_k2;
+ return;
}
/* Libmv returned distortion model which is not known to Blender. This is a logical error in code
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 9d9e8423bcf..1098ad6d95c 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -795,12 +795,52 @@ bool BKE_volume_is_points_only(const Volume *volume)
/* Dependency Graph */
-static Volume *volume_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph),
- struct Scene *UNUSED(scene),
- Object *UNUSED(object),
+static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
Volume *volume_input)
{
- return volume_input;
+ Volume *volume = volume_input;
+
+ /* Modifier evaluation modes. */
+ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
+ const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(object, &virtualModifierData);
+
+ /* Evaluate modifiers. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = (const ModifierTypeInfo *)modifierType_getInfo(
+ (ModifierType)md->type);
+
+ if (!modifier_isEnabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if (mti->modifyVolume) {
+ /* Ensure we are not modifying the input. */
+ if (volume == volume_input) {
+ volume = BKE_volume_copy_for_eval(volume, true);
+ }
+
+ Volume *volume_next = mti->modifyVolume(md, &mectx, volume);
+
+ if (volume_next && volume_next != volume) {
+ /* If the modifier returned a new volume, release the old one. */
+ if (volume != volume_input) {
+ BKE_id_free(NULL, volume);
+ }
+ volume = volume_next;
+ }
+ }
+ }
+
+ return volume;
}
void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index f2219ad1cf8..3be62750673 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -59,7 +59,7 @@ static void world_free_data(ID *id)
/* is no lib link block, but world extension */
if (wrld->nodetree) {
- ntreeFreeNestedTree(wrld->nodetree);
+ ntreeFreeEmbeddedTree(wrld->nodetree);
MEM_freeN(wrld->nodetree);
wrld->nodetree = NULL;
}
diff --git a/source/blender/blenlib/BLI_allocator.h b/source/blender/blenlib/BLI_allocator.hh
index e2d39c4e897..c52db4aab53 100644
--- a/source/blender/blenlib/BLI_allocator.h
+++ b/source/blender/blenlib/BLI_allocator.hh
@@ -13,8 +13,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_ALLOCATOR_H__
-#define __BLI_ALLOCATOR_H__
+#ifndef __BLI_ALLOCATOR_HH__
+#define __BLI_ALLOCATOR_HH__
/** \file
* \ingroup bli
@@ -102,4 +102,4 @@ class RawAllocator {
} // namespace BLI
-#endif /* __BLI_ALLOCATOR_H__ */
+#endif /* __BLI_ALLOCATOR_HH__ */
diff --git a/source/blender/blenlib/BLI_array_cxx.h b/source/blender/blenlib/BLI_array.hh
index 8fc2aec6698..9dd8341aa76 100644
--- a/source/blender/blenlib/BLI_array_cxx.h
+++ b/source/blender/blenlib/BLI_array.hh
@@ -13,8 +13,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_ARRAY_CXX_H__
-#define __BLI_ARRAY_CXX_H__
+#ifndef __BLI_ARRAY_HH__
+#define __BLI_ARRAY_HH__
/** \file
* \ingroup bli
@@ -23,20 +23,21 @@
* a template argument. Instead it can be specified at the construction time.
*/
-#include "BLI_allocator.h"
-#include "BLI_array_ref.h"
-#include "BLI_index_range.h"
-#include "BLI_memory_utils_cxx.h"
+#include "BLI_allocator.hh"
+#include "BLI_array_ref.hh"
+#include "BLI_index_range.hh"
+#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
namespace BLI {
-template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Array {
+template<typename T, uint InlineBufferCapacity = 4, typename Allocator = GuardedAllocator>
+class Array {
private:
T *m_data;
uint m_size;
Allocator m_allocator;
- AlignedBuffer<sizeof(T) * N, alignof(T)> m_inline_storage;
+ AlignedBuffer<sizeof(T) * InlineBufferCapacity, alignof(T)> m_inline_storage;
public:
Array()
@@ -79,7 +80,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ar
m_allocator = other.m_allocator;
m_data = this->get_buffer_for_size(other.size());
- copy_n(other.begin(), m_size, m_data);
+ uninitialized_copy_n(other.begin(), m_size, m_data);
}
Array(Array &&other) noexcept
@@ -201,10 +202,15 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ar
return IndexRange(m_size);
}
+ Allocator &allocator()
+ {
+ return m_allocator;
+ }
+
private:
T *get_buffer_for_size(uint size)
{
- if (size <= N) {
+ if (size <= InlineBufferCapacity) {
return this->inline_storage();
}
else {
@@ -231,4 +237,4 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ar
} // namespace BLI
-#endif /* __BLI_ARRAY_CXX_H__ */
+#endif /* __BLI_ARRAY_HH__ */
diff --git a/source/blender/blenlib/BLI_array_ref.h b/source/blender/blenlib/BLI_array_ref.hh
index 2c2e441a47d..dd9421d289c 100644
--- a/source/blender/blenlib/BLI_array_ref.h
+++ b/source/blender/blenlib/BLI_array_ref.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_ARRAY_REF_H__
-#define __BLI_ARRAY_REF_H__
+#ifndef __BLI_ARRAY_REF_HH__
+#define __BLI_ARRAY_REF_HH__
/** \file
* \ingroup bli
@@ -41,8 +41,8 @@
#include <string>
#include <vector>
-#include "BLI_index_range.h"
-#include "BLI_memory_utils_cxx.h"
+#include "BLI_index_range.hh"
+#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
namespace BLI {
@@ -542,4 +542,4 @@ void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3)
} /* namespace BLI */
-#endif /* __BLI_ARRAY_REF_H__ */
+#endif /* __BLI_ARRAY_REF_HH__ */
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
new file mode 100644
index 00000000000..ff28ae2c076
--- /dev/null
+++ b/source/blender/blenlib/BLI_color.hh
@@ -0,0 +1,92 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_COLOR_HH__
+#define __BLI_COLOR_HH__
+
+#include <iostream>
+
+#include "BLI_math_color.h"
+
+namespace BLI {
+
+struct Color4f {
+ float r, g, b, a;
+
+ Color4f() = default;
+
+ Color4f(float r, float g, float b, float a) : r(r), g(g), b(b), a(a)
+ {
+ }
+
+ operator float *()
+ {
+ return &r;
+ }
+
+ operator const float *() const
+ {
+ return &r;
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, Color4f c)
+ {
+ stream << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
+ return stream;
+ }
+};
+
+struct Color4b {
+ uint8_t r, g, b, a;
+
+ Color4b() = default;
+
+ Color4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a)
+ {
+ }
+
+ Color4b(Color4f other)
+ {
+ rgba_float_to_uchar(*this, other);
+ }
+
+ operator Color4f() const
+ {
+ Color4f result;
+ rgba_uchar_to_float(result, *this);
+ return result;
+ }
+
+ operator uint8_t *()
+ {
+ return &r;
+ }
+
+ operator const uint8_t *() const
+ {
+ return &r;
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, Color4b c)
+ {
+ stream << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
+ return stream;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_COLOR_HH__ */
diff --git a/source/blender/blenlib/BLI_dot_export.hh b/source/blender/blenlib/BLI_dot_export.hh
new file mode 100644
index 00000000000..08c37fec01e
--- /dev/null
+++ b/source/blender/blenlib/BLI_dot_export.hh
@@ -0,0 +1,290 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_DOT_EXPORT_HH__
+#define __BLI_DOT_EXPORT_HH__
+
+/**
+ * Language grammar: https://www.graphviz.org/doc/info/lang.html
+ * Attributes: https://www.graphviz.org/doc/info/attrs.html
+ * Node Shapes: https://www.graphviz.org/doc/info/shapes.html
+ * Preview: https://dreampuf.github.io/GraphvizOnline
+ */
+
+#include "BLI_map.hh"
+#include "BLI_optional.hh"
+#include "BLI_set.hh"
+#include "BLI_string_map.hh"
+#include "BLI_utility_mixins.hh"
+#include "BLI_vector.hh"
+
+#include "BLI_dot_export_attribute_enums.hh"
+
+#include <sstream>
+
+namespace BLI {
+namespace DotExport {
+
+class Graph;
+class DirectedGraph;
+class UndirectedGraph;
+class Node;
+class NodePort;
+class DirectedEdge;
+class UndirectedEdge;
+class Cluster;
+class AttributeList;
+
+class AttributeList {
+ private:
+ Map<std::string, std::string> m_attributes;
+
+ public:
+ void export__as_bracket_list(std::stringstream &ss) const;
+
+ void set(StringRef key, StringRef value)
+ {
+ m_attributes.add_override(key, value);
+ }
+};
+
+class Graph {
+ private:
+ AttributeList m_attributes;
+ Vector<std::unique_ptr<Node>> m_nodes;
+ Vector<std::unique_ptr<Cluster>> m_clusters;
+
+ Set<Node *> m_top_level_nodes;
+ Set<Cluster *> m_top_level_clusters;
+
+ friend Cluster;
+ friend Node;
+
+ public:
+ Node &new_node(StringRef label);
+ Cluster &new_cluster(StringRef label = "");
+
+ void export__declare_nodes_and_clusters(std::stringstream &ss) const;
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+
+ void set_rankdir(Attr_rankdir rankdir)
+ {
+ this->set_attribute("rankdir", rankdir_to_string(rankdir));
+ }
+
+ void set_random_cluster_bgcolors();
+};
+
+class Cluster {
+ private:
+ AttributeList m_attributes;
+ Graph &m_graph;
+ Cluster *m_parent = nullptr;
+ Set<Cluster *> m_children;
+ Set<Node *> m_nodes;
+
+ friend Graph;
+ friend Node;
+
+ Cluster(Graph &graph) : m_graph(graph)
+ {
+ }
+
+ public:
+ void export__declare_nodes_and_clusters(std::stringstream &ss) const;
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+
+ void set_parent_cluster(Cluster *cluster);
+ void set_parent_cluster(Cluster &cluster)
+ {
+ this->set_parent_cluster(&cluster);
+ }
+
+ void set_random_cluster_bgcolors();
+};
+
+class Node {
+ private:
+ AttributeList m_attributes;
+ Graph &m_graph;
+ Cluster *m_cluster = nullptr;
+
+ friend Graph;
+
+ Node(Graph &graph) : m_graph(graph)
+ {
+ }
+
+ public:
+ const AttributeList &attributes() const
+ {
+ return m_attributes;
+ }
+
+ AttributeList &attributes()
+ {
+ return m_attributes;
+ }
+
+ void set_parent_cluster(Cluster *cluster);
+ void set_parent_cluster(Cluster &cluster)
+ {
+ this->set_parent_cluster(&cluster);
+ }
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+
+ void set_shape(Attr_shape shape)
+ {
+ this->set_attribute("shape", shape_to_string(shape));
+ }
+
+ /* See https://www.graphviz.org/doc/info/attrs.html#k:color. */
+ void set_background_color(StringRef name)
+ {
+ this->set_attribute("fillcolor", name);
+ this->set_attribute("style", "filled");
+ }
+
+ void export__as_id(std::stringstream &ss) const;
+
+ void export__as_declaration(std::stringstream &ss) const;
+};
+
+class UndirectedGraph final : public Graph {
+ private:
+ Vector<std::unique_ptr<UndirectedEdge>> m_edges;
+
+ public:
+ std::string to_dot_string() const;
+
+ UndirectedEdge &new_edge(NodePort a, NodePort b);
+};
+
+class DirectedGraph final : public Graph {
+ private:
+ Vector<std::unique_ptr<DirectedEdge>> m_edges;
+
+ public:
+ std::string to_dot_string() const;
+
+ DirectedEdge &new_edge(NodePort from, NodePort to);
+};
+
+class NodePort {
+ private:
+ Node *m_node;
+ Optional<std::string> m_port_name;
+
+ public:
+ NodePort(Node &node, Optional<std::string> port_name = {})
+ : m_node(&node), m_port_name(std::move(port_name))
+ {
+ }
+
+ void to_dot_string(std::stringstream &ss) const;
+};
+
+class Edge : BLI::NonCopyable, BLI::NonMovable {
+ protected:
+ AttributeList m_attributes;
+ NodePort m_a;
+ NodePort m_b;
+
+ public:
+ Edge(NodePort a, NodePort b) : m_a(std::move(a)), m_b(std::move(b))
+ {
+ }
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+
+ void set_arrowhead(Attr_arrowType type)
+ {
+ this->set_attribute("arrowhead", arrowType_to_string(type));
+ }
+
+ void set_arrowtail(Attr_arrowType type)
+ {
+ this->set_attribute("arrowtail", arrowType_to_string(type));
+ }
+
+ void set_dir(Attr_dirType type)
+ {
+ this->set_attribute("dir", dirType_to_string(type));
+ }
+};
+
+class DirectedEdge : public Edge {
+ public:
+ DirectedEdge(NodePort from, NodePort to) : Edge(std::move(from), std::move(to))
+ {
+ }
+
+ void export__as_edge_statement(std::stringstream &ss) const;
+};
+
+class UndirectedEdge : public Edge {
+ public:
+ UndirectedEdge(NodePort a, NodePort b) : Edge(std::move(a), std::move(b))
+ {
+ }
+
+ void export__as_edge_statement(std::stringstream &ss) const;
+};
+
+std::string color_attr_from_hsv(float h, float s, float v);
+
+class NodeWithSocketsRef {
+ private:
+ Node *m_node;
+
+ public:
+ NodeWithSocketsRef(Node &node,
+ StringRef name,
+ ArrayRef<std::string> input_names,
+ ArrayRef<std::string> output_names);
+
+ NodePort input(uint index) const
+ {
+ std::string port = "\"in" + std::to_string(index) + "\"";
+ return NodePort(*m_node, port);
+ }
+
+ NodePort output(uint index) const
+ {
+ std::string port = "\"out" + std::to_string(index) + "\"";
+ return NodePort(*m_node, port);
+ }
+};
+
+} // namespace DotExport
+} // namespace BLI
+
+#endif /* __BLI_DOT_EXPORT_HH__ */
diff --git a/source/blender/blenlib/BLI_dot_export_attribute_enums.hh b/source/blender/blenlib/BLI_dot_export_attribute_enums.hh
new file mode 100644
index 00000000000..8e61f46dc12
--- /dev/null
+++ b/source/blender/blenlib/BLI_dot_export_attribute_enums.hh
@@ -0,0 +1,125 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_DOT_EXPORT_ATTRIBUTE_ENUMS_HH__
+#define __BLI_DOT_EXPORT_ATTRIBUTE_ENUMS_HH__
+
+#include "BLI_string_ref.hh"
+
+namespace BLI {
+namespace DotExport {
+
+enum class Attr_rankdir {
+ LeftToRight,
+ TopToBottom,
+};
+
+inline StringRef rankdir_to_string(Attr_rankdir value)
+{
+ switch (value) {
+ case Attr_rankdir::LeftToRight:
+ return "LR";
+ case Attr_rankdir::TopToBottom:
+ return "TB";
+ }
+ return "";
+}
+
+enum class Attr_shape {
+ Rectangle,
+ Ellipse,
+ Circle,
+ Point,
+ Diamond,
+ Square,
+};
+
+inline StringRef shape_to_string(Attr_shape value)
+{
+ switch (value) {
+ case Attr_shape::Rectangle:
+ return "rectangle";
+ case Attr_shape::Ellipse:
+ return "ellipse";
+ case Attr_shape::Circle:
+ return "circle";
+ case Attr_shape::Point:
+ return "point";
+ case Attr_shape::Diamond:
+ return "diamond";
+ case Attr_shape::Square:
+ return "square";
+ }
+ return "";
+}
+
+enum class Attr_arrowType {
+ Normal,
+ Inv,
+ Dot,
+ None,
+ Empty,
+ Box,
+ Vee,
+};
+
+inline StringRef arrowType_to_string(Attr_arrowType value)
+{
+ switch (value) {
+ case Attr_arrowType::Normal:
+ return "normal";
+ case Attr_arrowType::Inv:
+ return "inv";
+ case Attr_arrowType::Dot:
+ return "dot";
+ case Attr_arrowType::None:
+ return "none";
+ case Attr_arrowType::Empty:
+ return "empty";
+ case Attr_arrowType::Box:
+ return "box";
+ case Attr_arrowType::Vee:
+ return "vee";
+ }
+ return "";
+}
+
+enum class Attr_dirType {
+ Forward,
+ Back,
+ Both,
+ None,
+};
+
+inline StringRef dirType_to_string(Attr_dirType value)
+{
+ switch (value) {
+ case Attr_dirType::Forward:
+ return "forward";
+ case Attr_dirType::Back:
+ return "back";
+ case Attr_dirType::Both:
+ return "both";
+ case Attr_dirType::None:
+ return "none";
+ }
+ return "";
+}
+
+} // namespace DotExport
+} // namespace BLI
+
+#endif /* __BLI_DOT_EXPORT_ATTRIBUTE_ENUMS_HH__ */
diff --git a/source/blender/blenlib/BLI_float2.hh b/source/blender/blenlib/BLI_float2.hh
new file mode 100644
index 00000000000..da12dd7d206
--- /dev/null
+++ b/source/blender/blenlib/BLI_float2.hh
@@ -0,0 +1,86 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_FLOAT2_HH__
+#define __BLI_FLOAT2_HH__
+
+#include "BLI_float3.hh"
+
+namespace BLI {
+
+struct float2 {
+ float x, y;
+
+ float2() = default;
+
+ float2(const float *ptr) : x{ptr[0]}, y{ptr[1]}
+ {
+ }
+
+ float2(float x, float y) : x(x), y(y)
+ {
+ }
+
+ float2(const float3 &other) : x(other.x), y(other.y)
+ {
+ }
+
+ operator float *()
+ {
+ return &x;
+ }
+
+ operator const float *() const
+ {
+ return &x;
+ }
+
+ friend float2 operator+(const float2 &a, const float2 &b)
+ {
+ return {a.x + b.x, a.y + b.y};
+ }
+
+ friend float2 operator-(const float2 &a, const float2 &b)
+ {
+ return {a.x - b.x, a.y - b.y};
+ }
+
+ friend float2 operator*(const float2 &a, float b)
+ {
+ return {a.x * b, a.y * b};
+ }
+
+ friend float2 operator/(const float2 &a, float b)
+ {
+ BLI_assert(b != 0.0f);
+ return {a.x / b, a.y / b};
+ }
+
+ friend float2 operator*(float a, const float2 &b)
+ {
+ return b * a;
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, const float2 &v)
+ {
+ stream << "(" << v.x << ", " << v.y << ")";
+ return stream;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_FLOAT2_HH__ */
diff --git a/source/blender/blenlib/BLI_float3.hh b/source/blender/blenlib/BLI_float3.hh
new file mode 100644
index 00000000000..9678fa4b2d3
--- /dev/null
+++ b/source/blender/blenlib/BLI_float3.hh
@@ -0,0 +1,218 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_FLOAT3_HH__
+#define __BLI_FLOAT3_HH__
+
+#include <iostream>
+
+#include "BLI_math_vector.h"
+
+namespace BLI {
+
+struct float3 {
+ float x, y, z;
+
+ float3() = default;
+
+ float3(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}
+ {
+ }
+
+ float3(const float (*ptr)[3]) : float3((const float *)ptr)
+ {
+ }
+
+ explicit float3(float value) : x(value), y(value), z(value)
+ {
+ }
+
+ explicit float3(int value) : x(value), y(value), z(value)
+ {
+ }
+
+ float3(float x, float y, float z) : x{x}, y{y}, z{z}
+ {
+ }
+
+ operator const float *() const
+ {
+ return &x;
+ }
+
+ operator float *()
+ {
+ return &x;
+ }
+
+ float normalize_and_get_length()
+ {
+ return normalize_v3(*this);
+ }
+
+ float3 normalized() const
+ {
+ float3 result;
+ normalize_v3_v3(result, *this);
+ return result;
+ }
+
+ float length() const
+ {
+ return len_v3(*this);
+ }
+
+ float length_squared() const
+ {
+ return len_squared_v3(*this);
+ }
+
+ void reflect(const float3 &normal)
+ {
+ *this = this->reflected(normal);
+ }
+
+ float3 reflected(const float3 &normal) const
+ {
+ float3 result;
+ reflect_v3_v3v3(result, *this, normal);
+ return result;
+ }
+
+ static float3 safe_divide(const float3 &a, const float3 &b)
+ {
+ float3 result;
+ result.x = (b.x == 0.0f) ? 0.0f : a.x / b.x;
+ result.y = (b.y == 0.0f) ? 0.0f : a.y / b.y;
+ result.z = (b.z == 0.0f) ? 0.0f : a.z / b.z;
+ return result;
+ }
+
+ void invert()
+ {
+ x = -x;
+ y = -y;
+ z = -z;
+ }
+
+ friend float3 operator+(const float3 &a, const float3 &b)
+ {
+ return {a.x + b.x, a.y + b.y, a.z + b.z};
+ }
+
+ void operator+=(const float3 &b)
+ {
+ this->x += b.x;
+ this->y += b.y;
+ this->z += b.z;
+ }
+
+ friend float3 operator-(const float3 &a, const float3 &b)
+ {
+ return {a.x - b.x, a.y - b.y, a.z - b.z};
+ }
+
+ friend float3 operator-(const float3 &a)
+ {
+ return {-a.x, -a.y, -a.z};
+ }
+
+ void operator-=(const float3 &b)
+ {
+ this->x -= b.x;
+ this->y -= b.y;
+ this->z -= b.z;
+ }
+
+ void operator*=(float scalar)
+ {
+ this->x *= scalar;
+ this->y *= scalar;
+ this->z *= scalar;
+ }
+
+ void operator*=(const float3 &other)
+ {
+ this->x *= other.x;
+ this->y *= other.y;
+ this->z *= other.z;
+ }
+
+ friend float3 operator*(const float3 &a, const float3 &b)
+ {
+ return {a.x * b.x, a.y * b.y, a.z * b.z};
+ }
+
+ friend float3 operator*(const float3 &a, float b)
+ {
+ return {a.x * b, a.y * b, a.z * b};
+ }
+
+ friend float3 operator*(float a, const float3 &b)
+ {
+ return b * a;
+ }
+
+ friend float3 operator/(const float3 &a, float b)
+ {
+ BLI_assert(b != 0.0f);
+ return {a.x / b, a.y / b, a.z / b};
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, const float3 &v)
+ {
+ stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
+ return stream;
+ }
+
+ static float dot(const float3 &a, const float3 &b)
+ {
+ return a.x * b.x + a.y * b.y + a.z * b.z;
+ }
+
+ static float3 cross_high_precision(const float3 &a, const float3 &b)
+ {
+ float3 result;
+ cross_v3_v3v3_hi_prec(result, a, b);
+ return result;
+ }
+
+ static float3 project(const float3 &a, const float3 &b)
+ {
+ float3 result;
+ project_v3_v3v3(result, a, b);
+ return result;
+ }
+
+ static float distance(const float3 &a, const float3 &b)
+ {
+ return (a - b).length();
+ }
+
+ static float distance_squared(const float3 &a, const float3 &b)
+ {
+ return float3::dot(a, b);
+ }
+
+ static float3 interpolate(const float3 &a, const float3 &b, float t)
+ {
+ return a * (1 - t) + b * t;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_FLOAT3_HH__ */
diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh
new file mode 100644
index 00000000000..36186d319c9
--- /dev/null
+++ b/source/blender/blenlib/BLI_float4x4.hh
@@ -0,0 +1,115 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_FLOAT4X4_HH__
+#define __BLI_FLOAT4X4_HH__
+
+#include "BLI_float3.hh"
+#include "BLI_math_matrix.h"
+
+namespace BLI {
+
+struct float4x4 {
+ float values[4][4];
+
+ float4x4() = default;
+
+ float4x4(const float *matrix)
+ {
+ memcpy(values, matrix, sizeof(float) * 16);
+ }
+
+ float4x4(const float matrix[4][4]) : float4x4((float *)matrix)
+ {
+ }
+
+ operator float *()
+ {
+ return (float *)this;
+ }
+
+ operator const float *() const
+ {
+ return (const float *)this;
+ }
+
+ float4x4 inverted() const
+ {
+ float result[4][4];
+ invert_m4_m4(result, values);
+ return result;
+ }
+
+ /**
+ * Matrix inversion can be implemented more efficiently for affine matrices.
+ */
+ float4x4 inverted_affine() const
+ {
+ BLI_assert(values[0][3] == 0.0f && values[1][3] == 0.0f && values[2][3] == 0.0f &&
+ values[3][3] == 1.0f);
+ return this->inverted();
+ }
+
+ friend float4x4 operator*(const float4x4 &a, const float4x4 &b)
+ {
+ float4x4 result;
+ mul_m4_m4m4(result.values, a.values, b.values);
+ return result;
+ }
+
+ /**
+ * This also applies the translation on the vector. Use `m.ref_3x3() * v` if that is not
+ * intended.
+ */
+ friend float3 operator*(const float4x4 &m, const float3 &v)
+ {
+ float3 result;
+ mul_v3_m4v3(result, m.values, v);
+ return result;
+ }
+
+ friend float3 operator*(const float4x4 &m, const float (*v)[3])
+ {
+ return m * float3(v);
+ }
+
+ struct float3x3_ref {
+ const float4x4 &data;
+
+ friend float3 operator*(const float3x3_ref &m, const float3 &v)
+ {
+ float3 result;
+ mul_v3_mat3_m4v3(result, m.data.values, v);
+ return result;
+ }
+ };
+
+ float3x3_ref ref_3x3() const
+ {
+ return {*this};
+ }
+
+ static float4x4 interpolate(const float4x4 &a, const float4x4 &b, float t)
+ {
+ float result[4][4];
+ interp_m4_m4m4(result, a.values, b.values, t);
+ return result;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_FLOAT4X4_HH__ */
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index dffb2a165ee..b69bdb7057c 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -24,6 +24,8 @@
* \ingroup bli
*/
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h
index d09291b64be..3871ddf956a 100644
--- a/source/blender/blenlib/BLI_hash.h
+++ b/source/blender/blenlib/BLI_hash.h
@@ -81,7 +81,7 @@ BLI_INLINE void BLI_hash_pointer_to_color(const void *ptr, int *r, int *g, int *
{
size_t val = (size_t)ptr;
const size_t hash_a = BLI_hash_int(val & 0x0000ffff);
- const size_t hash_b = BLI_hash_int((uint)((val & 0xffff0000) >> 32));
+ const size_t hash_b = BLI_hash_int((uint)((val & 0xffff0000) >> 16));
const size_t hash = hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
*r = (hash & 0xff0000) >> 16;
*g = (hash & 0x00ff00) >> 8;
diff --git a/source/blender/blenlib/BLI_hash_cxx.h b/source/blender/blenlib/BLI_hash.hh
index 22941a792ba..3b3448f66b1 100644
--- a/source/blender/blenlib/BLI_hash_cxx.h
+++ b/source/blender/blenlib/BLI_hash.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_HASH_CXX_H__
-#define __BLI_HASH_CXX_H__
+#ifndef __BLI_HASH_HH__
+#define __BLI_HASH_HH__
/** \file
* \ingroup bli
@@ -30,6 +30,7 @@
#include <utility>
#include "BLI_math_base.h"
+#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
namespace BLI {
@@ -67,14 +68,33 @@ template<> struct DefaultHash<float> {
}
};
+inline uint32_t hash_string(StringRef str)
+{
+ uint32_t hash = 5381;
+ for (char c : str) {
+ hash = hash * 33 + c;
+ }
+ return hash;
+}
+
template<> struct DefaultHash<std::string> {
uint32_t operator()(const std::string &value) const
{
- uint32_t hash = 5381;
- for (char c : value) {
- hash = hash * 33 + c;
- }
- return hash;
+ return hash_string(value);
+ }
+};
+
+template<> struct DefaultHash<StringRef> {
+ uint32_t operator()(const StringRef &value) const
+ {
+ return hash_string(value);
+ }
+};
+
+template<> struct DefaultHash<StringRefNull> {
+ uint32_t operator()(const StringRefNull &value) const
+ {
+ return hash_string(value);
}
};
@@ -109,4 +129,4 @@ template<typename T1, typename T2> struct DefaultHash<std::pair<T1, T2>> {
} // namespace BLI
-#endif /* __BLI_HASH_CXX_H__ */
+#endif /* __BLI_HASH_HH__ */
diff --git a/source/blender/blenlib/BLI_index_range.h b/source/blender/blenlib/BLI_index_range.hh
index 4553c996454..e24fd567810 100644
--- a/source/blender/blenlib/BLI_index_range.h
+++ b/source/blender/blenlib/BLI_index_range.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_INDEX_RANGE_H__
-#define __BLI_INDEX_RANGE_H__
+#ifndef __BLI_INDEX_RANGE_HH__
+#define __BLI_INDEX_RANGE_HH__
/** \file
* \ingroup bli
@@ -208,4 +208,4 @@ class IndexRange {
} // namespace BLI
-#endif /* __BLI_INDEX_RANGE_H__ */
+#endif /* __BLI_INDEX_RANGE_HH__ */
diff --git a/source/blender/blenlib/BLI_lasso_2d.h b/source/blender/blenlib/BLI_lasso_2d.h
index 56db360dab0..fb661c41784 100644
--- a/source/blender/blenlib/BLI_lasso_2d.h
+++ b/source/blender/blenlib/BLI_lasso_2d.h
@@ -30,14 +30,14 @@ extern "C" {
struct rcti;
-void BLI_lasso_boundbox(struct rcti *rect, const int mcords[][2], const unsigned int moves);
-bool BLI_lasso_is_point_inside(const int mcords[][2],
- const unsigned int moves,
+void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], const unsigned int mcoords_len);
+bool BLI_lasso_is_point_inside(const int mcoords[][2],
+ const unsigned int mcoords_len,
const int sx,
const int sy,
const int error_value);
-bool BLI_lasso_is_edge_inside(const int mcords[][2],
- const unsigned int moves,
+bool BLI_lasso_is_edge_inside(const int mcoords[][2],
+ const unsigned int mcoords_len,
int x0,
int y0,
int x1,
diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh
new file mode 100644
index 00000000000..cebf878580c
--- /dev/null
+++ b/source/blender/blenlib/BLI_linear_allocator.hh
@@ -0,0 +1,173 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ *
+ * A linear allocator is the simplest form of an allocator. It never reuses any memory, and
+ * therefore does not need a deallocation method. It simply hands out consecutive buffers of
+ * memory. When the current buffer is full, it reallocates a new larger buffer and continues.
+ */
+
+#ifndef __BLI_LINEAR_ALLOCATOR_HH__
+#define __BLI_LINEAR_ALLOCATOR_HH__
+
+#include "BLI_string_ref.hh"
+#include "BLI_utility_mixins.hh"
+#include "BLI_vector.hh"
+
+namespace BLI {
+
+template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopyable, NonMovable {
+ private:
+ Allocator m_allocator;
+ Vector<void *> m_owned_buffers;
+ Vector<ArrayRef<char>> m_unused_borrowed_buffers;
+
+ uintptr_t m_current_begin;
+ uintptr_t m_current_end;
+ uint m_next_min_alloc_size;
+
+#ifdef DEBUG
+ uint m_debug_allocated_amount = 0;
+#endif
+
+ public:
+ LinearAllocator()
+ {
+ m_current_begin = 0;
+ m_current_end = 0;
+ m_next_min_alloc_size = 64;
+ }
+
+ ~LinearAllocator()
+ {
+ for (void *ptr : m_owned_buffers) {
+ m_allocator.deallocate(ptr);
+ }
+ }
+
+ void provide_buffer(void *buffer, uint size)
+ {
+ m_unused_borrowed_buffers.append(ArrayRef<char>((char *)buffer, size));
+ }
+
+ template<uint Size, uint Alignment>
+ void provide_buffer(AlignedBuffer<Size, Alignment> &aligned_buffer)
+ {
+ this->provide_buffer(aligned_buffer.ptr(), Size);
+ }
+
+ template<typename T> T *allocate()
+ {
+ return (T *)this->allocate(sizeof(T), alignof(T));
+ }
+
+ template<typename T> MutableArrayRef<T> allocate_array(uint length)
+ {
+ return MutableArrayRef<T>((T *)this->allocate(sizeof(T) * length), length);
+ }
+
+ void *allocate(uint size, uint alignment = 4)
+ {
+ BLI_assert(alignment >= 1);
+ BLI_assert(is_power_of_2_i(alignment));
+
+#ifdef DEBUG
+ m_debug_allocated_amount += size;
+#endif
+
+ uintptr_t alignment_mask = alignment - 1;
+ uintptr_t potential_allocation_begin = (m_current_begin + alignment_mask) & ~alignment_mask;
+ uintptr_t potential_allocation_end = potential_allocation_begin + size;
+
+ if (potential_allocation_end <= m_current_end) {
+ m_current_begin = potential_allocation_end;
+ return (void *)potential_allocation_begin;
+ }
+ else {
+ this->allocate_new_buffer(size + alignment);
+ return this->allocate(size, alignment);
+ }
+ };
+
+ StringRefNull copy_string(StringRef str)
+ {
+ uint alloc_size = str.size() + 1;
+ char *buffer = (char *)this->allocate(alloc_size, 1);
+ str.copy(buffer, alloc_size);
+ return StringRefNull((const char *)buffer);
+ }
+
+ template<typename T, typename... Args> T *construct(Args &&... args)
+ {
+ void *buffer = this->allocate(sizeof(T), alignof(T));
+ T *value = new (buffer) T(std::forward<Args>(args)...);
+ return value;
+ }
+
+ template<typename T, typename... Args>
+ ArrayRef<T *> construct_elements_and_pointer_array(uint n, Args &&... args)
+ {
+ void *pointer_buffer = this->allocate(n * sizeof(T *), alignof(T *));
+ void *element_buffer = this->allocate(n * sizeof(T), alignof(T));
+
+ MutableArrayRef<T *> pointers((T **)pointer_buffer, n);
+ T *elements = (T *)element_buffer;
+
+ for (uint i : IndexRange(n)) {
+ pointers[i] = elements + i;
+ }
+ for (uint i : IndexRange(n)) {
+ new (elements + i) T(std::forward<Args>(args)...);
+ }
+
+ return pointers;
+ }
+
+ template<typename T> MutableArrayRef<T> construct_array_copy(ArrayRef<T> source)
+ {
+ T *buffer = (T *)this->allocate(source.byte_size(), alignof(T));
+ uninitialized_copy_n(source.begin(), source.size(), buffer);
+ return MutableArrayRef<T>(buffer, source.size());
+ }
+
+ private:
+ void allocate_new_buffer(uint min_allocation_size)
+ {
+ for (uint i : m_unused_borrowed_buffers.index_range()) {
+ ArrayRef<char> buffer = m_unused_borrowed_buffers[i];
+ if (buffer.size() >= min_allocation_size) {
+ m_unused_borrowed_buffers.remove_and_reorder(i);
+ m_current_begin = (uintptr_t)buffer.begin();
+ m_current_end = (uintptr_t)buffer.end();
+ return;
+ }
+ }
+
+ uint size_in_bytes = power_of_2_min_u(std::max(min_allocation_size, m_next_min_alloc_size));
+ m_next_min_alloc_size = size_in_bytes * 2;
+
+ void *buffer = m_allocator.allocate(size_in_bytes, __func__);
+ m_owned_buffers.append(buffer);
+ m_current_begin = (uintptr_t)buffer;
+ m_current_end = m_current_begin + size_in_bytes;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_LINEAR_ALLOCATOR_HH__ */
diff --git a/source/blender/blenlib/BLI_listbase_wrapper.h b/source/blender/blenlib/BLI_listbase_wrapper.hh
index d6832166e35..02313d9d22d 100644
--- a/source/blender/blenlib/BLI_listbase_wrapper.h
+++ b/source/blender/blenlib/BLI_listbase_wrapper.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_LISTBASE_WRAPPER_H__
-#define __BLI_LISTBASE_WRAPPER_H__
+#ifndef __BLI_LISTBASE_WRAPPER_HH__
+#define __BLI_LISTBASE_WRAPPER_HH__
/** \file
* \ingroup bli
@@ -29,17 +29,17 @@
namespace BLI {
-template<typename T> class IntrusiveListBaseWrapper {
+template<typename T> class ListBaseWrapper {
private:
ListBase *m_listbase;
public:
- IntrusiveListBaseWrapper(ListBase *listbase) : m_listbase(listbase)
+ ListBaseWrapper(ListBase *listbase) : m_listbase(listbase)
{
BLI_assert(listbase);
}
- IntrusiveListBaseWrapper(ListBase &listbase) : IntrusiveListBaseWrapper(&listbase)
+ ListBaseWrapper(ListBase &listbase) : ListBaseWrapper(&listbase)
{
}
@@ -110,4 +110,4 @@ template<typename T> class IntrusiveListBaseWrapper {
} /* namespace BLI */
-#endif /* __BLI_LISTBASE_WRAPPER_H__ */
+#endif /* __BLI_LISTBASE_WRAPPER_HH__ */
diff --git a/source/blender/blenlib/BLI_map.h b/source/blender/blenlib/BLI_map.hh
index 4b7ac0791d9..ea5e5da4099 100644
--- a/source/blender/blenlib/BLI_map.h
+++ b/source/blender/blenlib/BLI_map.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_MAP_H__
-#define __BLI_MAP_H__
+#ifndef __BLI_MAP_HH__
+#define __BLI_MAP_HH__
/** \file
* \ingroup bli
@@ -26,9 +26,9 @@
* lookups. Keys and values are stored in groups of four to avoid wasting memory due to padding.
*/
-#include "BLI_array_ref.h"
-#include "BLI_hash_cxx.h"
-#include "BLI_open_addressing.h"
+#include "BLI_array_ref.hh"
+#include "BLI_hash.hh"
+#include "BLI_open_addressing.hh"
namespace BLI {
@@ -53,7 +53,11 @@ namespace BLI {
// clang-format on
-template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> class Map {
+template<typename KeyT,
+ typename ValueT,
+ uint32_t InlineBufferCapacity = 4,
+ typename Allocator = GuardedAllocator>
+class Map {
private:
static constexpr uint OFFSET_MASK = 3;
static constexpr uint OFFSET_SHIFT = 2;
@@ -65,8 +69,8 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
static constexpr uint8_t IS_DUMMY = 2;
uint8_t m_status[4];
- char m_keys[4 * sizeof(KeyT)];
- char m_values[4 * sizeof(ValueT)];
+ AlignedBuffer<4 * sizeof(KeyT), alignof(KeyT)> m_keys_buffer;
+ AlignedBuffer<4 * sizeof(ValueT), alignof(ValueT)> m_values_buffer;
public:
static constexpr uint slots_per_item = 4;
@@ -134,20 +138,18 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
KeyT *key(uint offset) const
{
- return (KeyT *)(m_keys + offset * sizeof(KeyT));
+ return (KeyT *)m_keys_buffer.ptr() + offset;
}
ValueT *value(uint offset) const
{
- return (ValueT *)(m_values + offset * sizeof(ValueT));
+ return (ValueT *)m_values_buffer.ptr() + offset;
}
template<typename ForwardKeyT, typename ForwardValueT>
void store(uint offset, ForwardKeyT &&key, ForwardValueT &&value)
{
- BLI_assert(m_status[offset] != IS_SET);
- m_status[offset] = IS_SET;
- new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key));
+ this->store_without_value(offset, std::forward<ForwardKeyT>(key));
new (this->value(offset)) ValueT(std::forward<ForwardValueT>(value));
}
@@ -167,7 +169,7 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
}
};
- using ArrayType = OpenAddressingArray<Item, 1, Allocator>;
+ using ArrayType = OpenAddressingArray<Item, InlineBufferCapacity, Allocator>;
ArrayType m_array;
public:
@@ -351,6 +353,12 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
ITER_SLOTS_END(offset);
}
+ ValueT *lookup_ptr(const KeyT &key)
+ {
+ const Map *const_this = this;
+ return const_cast<ValueT *>(const_this->lookup_ptr(key));
+ }
+
/**
* Lookup the value that corresponds to the key.
* Asserts when the key does not exist.
@@ -362,12 +370,6 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
return *ptr;
}
- ValueT *lookup_ptr(const KeyT &key)
- {
- const Map *const_this = this;
- return const_cast<ValueT *>(const_this->lookup_ptr(key));
- }
-
ValueT &lookup(const KeyT &key)
{
const Map *const_this = this;
@@ -406,6 +408,19 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
}
/**
+ * Return the value that corresponds to the given key.
+ * If it does not exist yet, insert a new default constructed value and return that.
+ */
+ ValueT &lookup_or_add_default(const KeyT &key)
+ {
+ return this->lookup_or_add(key, []() { return ValueT(); });
+ }
+ ValueT &lookup_or_add_default(const KeyT &&key)
+ {
+ return this->lookup_or_add(std::move(key), []() { return ValueT(); });
+ }
+
+ /**
* Get the number of elements in the map.
*/
uint32_t size() const
@@ -413,6 +428,17 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
return m_array.slots_set();
}
+ /**
+ * Returns true if there are no elements in the map.
+ */
+ bool is_empty() const
+ {
+ return this->size() == 0;
+ }
+
+ /**
+ * Calls the given function for each key-value-pair.
+ */
template<typename FuncT> void foreach_item(const FuncT &func) const
{
for (const Item &item : m_array) {
@@ -733,4 +759,4 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
} // namespace BLI
-#endif /* __BLI_MAP_H__ */
+#endif /* __BLI_MAP_HH__ */
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 6cfa2d2ced6..a171ff1bb1c 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -62,6 +62,11 @@ MINLINE void swap_v4_v4(float a[4], float b[4]);
MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]);
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]);
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]);
+
+MINLINE void copy_v2_uchar(unsigned char r[2], const unsigned char a);
+MINLINE void copy_v3_uchar(unsigned char r[3], const unsigned char a);
+MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a);
+
/* char */
MINLINE void copy_v2_v2_char(char r[2], const char a[2]);
MINLINE void copy_v3_v3_char(char r[3], const char a[3]);
diff --git a/source/blender/blenlib/BLI_memory_utils_cxx.h b/source/blender/blenlib/BLI_memory_utils.hh
index 6534138315d..d9acf08a43f 100644
--- a/source/blender/blenlib/BLI_memory_utils_cxx.h
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_MEMORY_UTILS_CXX_H__
-#define __BLI_MEMORY_UTILS_CXX_H__
+#ifndef __BLI_MEMORY_UTILS_HH__
+#define __BLI_MEMORY_UTILS_HH__
/** \file
* \ingroup bli
@@ -120,4 +120,4 @@ template<uint Size, uint Alignment> class alignas(Alignment) AlignedBuffer {
} // namespace BLI
-#endif /* __BLI_MEMORY_UTILS_CXX_H__ */
+#endif /* __BLI_MEMORY_UTILS_HH__ */
diff --git a/source/blender/blenlib/BLI_open_addressing.h b/source/blender/blenlib/BLI_open_addressing.hh
index 6a0acd418eb..3bd932350d0 100644
--- a/source/blender/blenlib/BLI_open_addressing.h
+++ b/source/blender/blenlib/BLI_open_addressing.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_OPEN_ADDRESSING_H__
-#define __BLI_OPEN_ADDRESSING_H__
+#ifndef __BLI_OPEN_ADDRESSING_HH__
+#define __BLI_OPEN_ADDRESSING_HH__
/** \file
* \ingroup bli
@@ -33,28 +33,88 @@
#include <cmath>
-#include "BLI_allocator.h"
+#include "BLI_allocator.hh"
+#include "BLI_array.hh"
#include "BLI_math_base.h"
-#include "BLI_memory_utils_cxx.h"
+#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
namespace BLI {
-template<typename Item, uint32_t ItemsInSmallStorage = 1, typename Allocator = GuardedAllocator>
+/** \name Constexpr utility functions.
+ * \{ */
+
+inline constexpr int is_power_of_2_i_constexpr(int n)
+{
+ return (n & (n - 1)) == 0;
+}
+
+inline constexpr uint32_t log2_floor_u_constexpr(uint32_t x)
+{
+ return x <= 1 ? 0 : 1 + log2_floor_u_constexpr(x >> 1);
+}
+
+inline constexpr uint32_t log2_ceil_u_constexpr(uint32_t x)
+{
+ return (is_power_of_2_i_constexpr((int)x)) ? log2_floor_u_constexpr(x) :
+ log2_floor_u_constexpr(x) + 1;
+}
+
+template<typename IntT> inline constexpr IntT ceil_division(IntT x, IntT y)
+{
+ BLI_STATIC_ASSERT(!std::is_signed<IntT>::value, "");
+ return x / y + ((x % y) != 0);
+}
+
+template<typename IntT> inline constexpr IntT floor_division(IntT x, IntT y)
+{
+ BLI_STATIC_ASSERT(!std::is_signed<IntT>::value, "");
+ return x / y;
+}
+
+inline constexpr uint8_t compute_item_exponent(uint32_t min_usable_slots,
+ uint32_t slots_per_item,
+ uint32_t max_load_factor_numerator,
+ uint32_t max_load_factor_denominator)
+{
+ // uint64_t min_total_slots = ceil_division((uint64_t)min_usable_slots *
+ // (uint64_t)max_load_factor_denominator,
+ // (uint64_t)max_load_factor_numerator);
+ // uint32_t min_total_items = (uint32_t)ceil_division(min_total_slots, (uint64_t)slots_per_item);
+ // uint8_t item_exponent = (uint8_t)log2_ceil_u_constexpr(min_total_items);
+ // return item_exponent;
+
+ return (uint8_t)log2_ceil_u_constexpr((uint32_t)ceil_division(
+ ceil_division((uint64_t)min_usable_slots * (uint64_t)max_load_factor_denominator,
+ (uint64_t)max_load_factor_numerator),
+ (uint64_t)slots_per_item));
+}
+
+/** \} */
+
+template<typename Item,
+ uint32_t MinUsableSlotsInSmallStorage = 1,
+ typename Allocator = GuardedAllocator>
class OpenAddressingArray {
private:
- static constexpr uint32_t slots_per_item = Item::slots_per_item;
- static constexpr float max_load_factor = 0.5f;
+ static constexpr uint32_t s_max_load_factor_numerator = 1;
+ static constexpr uint32_t s_max_load_factor_denominator = 2;
+ static constexpr uint32_t s_slots_per_item = Item::slots_per_item;
+
+ static constexpr uint8_t s_small_storage_item_exponent = compute_item_exponent(
+ MinUsableSlotsInSmallStorage,
+ s_slots_per_item,
+ s_max_load_factor_numerator,
+ s_max_load_factor_denominator);
+ static constexpr uint32_t s_items_in_small_storage = 1u << s_small_storage_item_exponent;
/* Invariants:
* 2^m_item_exponent = m_item_amount
- * m_item_amount * slots_per_item = m_slots_total
+ * m_item_amount * s_slots_per_item = m_slots_total
* m_slot_mask = m_slots_total - 1
* m_slots_set_or_dummy < m_slots_total
*/
- /* Array containing the actual hash table. Might be a pointer to the inlined storage. */
- Item *m_items;
/* Number of items in the hash table. Must be a power of two. */
uint32_t m_item_amount;
/* Exponent of the current item amount. */
@@ -69,65 +129,28 @@ class OpenAddressingArray {
uint32_t m_slots_usable;
/* Can be used to map a hash value into the range of valid slot indices. */
uint32_t m_slot_mask;
- Allocator m_allocator;
- AlignedBuffer<sizeof(Item) * ItemsInSmallStorage, alignof(Item)> m_local_storage;
+
+ Array<Item, s_items_in_small_storage, Allocator> m_items;
public:
- explicit OpenAddressingArray(uint8_t item_exponent = 0)
+ explicit OpenAddressingArray(uint8_t item_exponent = s_small_storage_item_exponent)
{
- m_slots_total = ((uint32_t)1 << item_exponent) * slots_per_item;
+ m_item_exponent = item_exponent;
+ m_item_amount = 1u << item_exponent;
+ m_slots_total = m_item_amount * s_slots_per_item;
+ m_slot_mask = m_slots_total - 1;
m_slots_set_or_dummy = 0;
m_slots_dummy = 0;
- m_slots_usable = (uint32_t)((float)m_slots_total * max_load_factor);
- m_slot_mask = m_slots_total - 1;
- m_item_amount = m_slots_total / slots_per_item;
- m_item_exponent = item_exponent;
+ m_slots_usable = (uint32_t)floor_division((uint64_t)m_slots_total *
+ (uint64_t)s_max_load_factor_numerator,
+ (uint64_t)s_max_load_factor_denominator);
- if (m_item_amount <= ItemsInSmallStorage) {
- m_items = this->small_storage();
- }
- else {
- m_items = (Item *)m_allocator.allocate_aligned(
- (uint32_t)sizeof(Item) * m_item_amount, std::alignment_of<Item>::value, __func__);
- }
-
- for (uint32_t i = 0; i < m_item_amount; i++) {
- new (m_items + i) Item();
- }
+ m_items = Array<Item, s_items_in_small_storage, Allocator>(m_item_amount);
}
- ~OpenAddressingArray()
- {
- if (m_items != nullptr) {
- for (uint32_t i = 0; i < m_item_amount; i++) {
- m_items[i].~Item();
- }
- if (!this->is_in_small_storage()) {
- m_allocator.deallocate((void *)m_items);
- }
- }
- }
-
- OpenAddressingArray(const OpenAddressingArray &other)
- {
- m_slots_total = other.m_slots_total;
- m_slots_set_or_dummy = other.m_slots_set_or_dummy;
- m_slots_dummy = other.m_slots_dummy;
- m_slots_usable = other.m_slots_usable;
- m_slot_mask = other.m_slot_mask;
- m_item_amount = other.m_item_amount;
- m_item_exponent = other.m_item_exponent;
-
- if (m_item_amount <= ItemsInSmallStorage) {
- m_items = this->small_storage();
- }
- else {
- m_items = (Item *)m_allocator.allocate_aligned(
- sizeof(Item) * m_item_amount, std::alignment_of<Item>::value, __func__);
- }
+ ~OpenAddressingArray() = default;
- uninitialized_copy_n(other.m_items, m_item_amount, m_items);
- }
+ OpenAddressingArray(const OpenAddressingArray &other) = default;
OpenAddressingArray(OpenAddressingArray &&other) noexcept
{
@@ -138,15 +161,8 @@ class OpenAddressingArray {
m_slot_mask = other.m_slot_mask;
m_item_amount = other.m_item_amount;
m_item_exponent = other.m_item_exponent;
- if (other.is_in_small_storage()) {
- m_items = this->small_storage();
- uninitialized_relocate_n(other.m_items, m_item_amount, m_items);
- }
- else {
- m_items = other.m_items;
- }
+ m_items = std::move(other.m_items);
- other.m_items = nullptr;
other.~OpenAddressingArray();
new (&other) OpenAddressingArray();
}
@@ -171,13 +187,19 @@ class OpenAddressingArray {
return *this;
}
+ Allocator &allocator()
+ {
+ return m_items.allocator();
+ }
+
/* Prepare a new array that can hold a minimum of min_usable_slots elements. All entries are
* empty. */
OpenAddressingArray init_reserved(uint32_t min_usable_slots) const
{
- float min_total_slots = (float)min_usable_slots / max_load_factor;
- uint32_t min_total_items = (uint32_t)std::ceil(min_total_slots / (float)slots_per_item);
- uint8_t item_exponent = (uint8_t)log2_ceil_u(min_total_items);
+ uint8_t item_exponent = compute_item_exponent(min_usable_slots,
+ s_slots_per_item,
+ s_max_load_factor_numerator,
+ s_max_load_factor_denominator);
OpenAddressingArray grown(item_exponent);
grown.m_slots_set_or_dummy = this->slots_set();
return grown;
@@ -270,36 +292,25 @@ class OpenAddressingArray {
Item *begin()
{
- return m_items;
+ return m_items.begin();
}
Item *end()
{
- return m_items + m_item_amount;
+ return m_items.end();
}
const Item *begin() const
{
- return m_items;
+ return m_items.begin();
}
const Item *end() const
{
- return m_items + m_item_amount;
- }
-
- private:
- Item *small_storage() const
- {
- return reinterpret_cast<Item *>((char *)m_local_storage.ptr());
- }
-
- bool is_in_small_storage() const
- {
- return m_items == this->small_storage();
+ return m_items.end();
}
};
} // namespace BLI
-#endif /* __BLI_OPEN_ADDRESSING_H__ */
+#endif /* __BLI_OPEN_ADDRESSING_HH__ */
diff --git a/source/blender/blenlib/BLI_optional.h b/source/blender/blenlib/BLI_optional.hh
index 267c858e0f2..eac11293781 100644
--- a/source/blender/blenlib/BLI_optional.h
+++ b/source/blender/blenlib/BLI_optional.hh
@@ -20,10 +20,10 @@
* Simple version of std::optional, which is only available since C++17.
*/
-#ifndef __BLI_OPTIONAL_H__
-#define __BLI_OPTIONAL_H__
+#ifndef __BLI_OPTIONAL_HH__
+#define __BLI_OPTIONAL_HH__
-#include "BLI_memory_utils_cxx.h"
+#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
#include <algorithm>
@@ -196,4 +196,4 @@ template<typename T> class Optional {
} /* namespace BLI */
-#endif /* __BLI_OPTIONAL_H__ */
+#endif /* __BLI_OPTIONAL_HH__ */
diff --git a/source/blender/blenlib/BLI_set.h b/source/blender/blenlib/BLI_set.hh
index dc101add1a7..dc9df5d116a 100644
--- a/source/blender/blenlib/BLI_set.h
+++ b/source/blender/blenlib/BLI_set.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_SET_H__
-#define __BLI_SET_H__
+#ifndef __BLI_SET_HH__
+#define __BLI_SET_HH__
/** \file
* \ingroup bli
@@ -23,9 +23,9 @@
* This file provides a set implementation that uses open addressing with probing.
*/
-#include "BLI_hash_cxx.h"
-#include "BLI_open_addressing.h"
-#include "BLI_vector.h"
+#include "BLI_hash.hh"
+#include "BLI_open_addressing.hh"
+#include "BLI_vector.hh"
namespace BLI {
@@ -50,7 +50,8 @@ namespace BLI {
// clang-format on
-template<typename T, typename Allocator = GuardedAllocator> class Set {
+template<typename T, uint InlineBufferCapacity = 4, typename Allocator = GuardedAllocator>
+class Set {
private:
static constexpr uint OFFSET_MASK = 3;
static constexpr uint OFFSET_SHIFT = 2;
@@ -62,7 +63,7 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
static constexpr uint8_t IS_DUMMY = 2;
uint8_t m_status[4];
- char m_values[4 * sizeof(T)];
+ AlignedBuffer<4 * sizeof(T), alignof(T)> m_buffer;
public:
static constexpr uint slots_per_item = 4;
@@ -114,7 +115,7 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
T *value(uint offset) const
{
- return (T *)(m_values + offset * sizeof(T));
+ return (T *)m_buffer.ptr() + offset;
}
template<typename ForwardT> void store(uint offset, ForwardT &&value)
@@ -153,8 +154,8 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
}
};
- using ArrayType = OpenAddressingArray<Item, 1, Allocator>;
- ArrayType m_array = OpenAddressingArray<Item>();
+ using ArrayType = OpenAddressingArray<Item, InlineBufferCapacity, Allocator>;
+ ArrayType m_array;
public:
Set() = default;
@@ -202,6 +203,7 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
/**
* Add a new value to the set if it does not exist yet.
+ * Returns true of the value has been newly added.
*/
bool add(const T &value)
{
@@ -266,19 +268,26 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
ITER_SLOTS_END(offset);
}
- Vector<T> to_small_vector() const
+ /**
+ * Get the amount of values stored in the set.
+ */
+ uint32_t size() const
{
- Vector<T> vector;
- vector.reserve(this->size());
- for (const T &value : *this) {
- vector.append(value);
- }
- return vector;
+ return m_array.slots_set();
}
- uint32_t size() const
+ /**
+ * Return true if this set contains no elements.
+ */
+ bool is_empty() const
{
- return m_array.slots_set();
+ return this->size() == 0;
+ }
+
+ void clear()
+ {
+ this->~Set();
+ new (this) Set();
}
/**
@@ -480,4 +489,4 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
} // namespace BLI
-#endif /* __BLI_SET_H__ */
+#endif /* __BLI_SET_HH__ */
diff --git a/source/blender/blenlib/BLI_stack_cxx.h b/source/blender/blenlib/BLI_stack.hh
index a26318a3dcb..7f1f9f9cc10 100644
--- a/source/blender/blenlib/BLI_stack_cxx.h
+++ b/source/blender/blenlib/BLI_stack.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_STACK_CXX_H__
-#define __BLI_STACK_CXX_H__
+#ifndef __BLI_STACK_HH__
+#define __BLI_STACK_HH__
/** \file
* \ingroup bli
@@ -23,13 +23,14 @@
* Basic stack implementation with support for small object optimization.
*/
-#include "BLI_vector.h"
+#include "BLI_vector.hh"
namespace BLI {
-template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Stack {
+template<typename T, uint InlineBufferCapacity = 4, typename Allocator = GuardedAllocator>
+class Stack {
private:
- Vector<T, N, Allocator> m_elements;
+ Vector<T, InlineBufferCapacity, Allocator> m_elements;
public:
Stack() = default;
@@ -147,4 +148,4 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class St
} /* namespace BLI */
-#endif /* __BLI_STACK_CXX_H__ */
+#endif /* __BLI_STACK_HH__ */
diff --git a/source/blender/blenlib/BLI_string_map.h b/source/blender/blenlib/BLI_string_map.hh
index f304b140bcc..ed23ea3aaa0 100644
--- a/source/blender/blenlib/BLI_string_map.h
+++ b/source/blender/blenlib/BLI_string_map.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_STRING_MAP_H__
-#define __BLI_STRING_MAP_H__
+#ifndef __BLI_STRING_MAP_HH__
+#define __BLI_STRING_MAP_HH__
/** \file
* \ingroup bli
@@ -27,10 +27,10 @@
* make it more efficient later on. Also, even if we will never implement this optimization, having
* a special map with string keys can be quite handy. */
-#include "BLI_map.h"
-#include "BLI_optional.h"
-#include "BLI_string_ref.h"
-#include "BLI_vector.h"
+#include "BLI_map.hh"
+#include "BLI_optional.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
namespace BLI {
@@ -156,10 +156,15 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
template<typename ForwardT>
void store(uint offset, uint32_t hash, uint32_t index, ForwardT &&value)
{
+ this->store_without_value(offset, hash, index);
+ new (this->value(offset)) T(std::forward<ForwardT>(value));
+ }
+
+ void store_without_value(uint offset, uint32_t hash, uint32_t index)
+ {
BLI_assert(!this->is_set(offset));
m_hashes[offset] = hash;
m_indices[offset] = index;
- new (this->value(offset)) T(std::forward<ForwardT>(value));
}
};
@@ -195,15 +200,51 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
*/
void add(StringRef key, const T &value)
{
- if (!this->contains(key)) {
- this->add_new(key, value);
- }
+ this->add__impl(key, value);
}
void add(StringRef key, T &&value)
{
- if (!this->contains(key)) {
- this->add_new(key, std::move(value));
+ this->add__impl(key, std::move(value));
+ }
+
+ /**
+ * First, checks if the key exists in the map.
+ * If it does exist, call the modify function with a pointer to the corresponding value.
+ * If it does not exist, call the create function with a pointer to where the value should be
+ * created.
+ *
+ * Returns whatever is returned from one of the callback functions. Both callbacks have to return
+ * the same type.
+ *
+ * CreateValueF: Takes a pointer to where the value should be created.
+ * ModifyValueF: Takes a pointer to the value that should be modified.
+ */
+ template<typename CreateValueF, typename ModifyValueF>
+ auto add_or_modify(StringRef key,
+ const CreateValueF &create_value,
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+ {
+ using CreateReturnT = decltype(create_value(nullptr));
+ using ModifyReturnT = decltype(modify_value(nullptr));
+ BLI_STATIC_ASSERT((std::is_same<CreateReturnT, ModifyReturnT>::value),
+ "Both callbacks should return the same type.");
+
+ this->ensure_can_add();
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ m_array.update__empty_to_set();
+ uint32_t index = this->save_key_in_array(key);
+ item.store_without_value(offset, hash, index);
+ T *value_ptr = item.value(offset);
+ return create_value(value_ptr);
+ }
+ else if (item.has_hash(offset, hash) && item.has_exact_key(offset, key, m_chars)) {
+ T *value_ptr = item.value(offset);
+ return modify_value(value_ptr);
+ }
}
+ ITER_SLOTS_END(offset);
}
/**
@@ -435,6 +476,24 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
ITER_SLOTS_END(offset);
}
+ template<typename ForwardT> bool add__impl(StringRef key, ForwardT &&value)
+ {
+ this->ensure_can_add();
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ uint32_t index = this->save_key_in_array(key);
+ item.store(offset, hash, index, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ return true;
+ }
+ else if (item.has_hash(offset, hash) && item.has_exact_key(offset, key, m_chars)) {
+ return false;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
template<typename ForwardT> void add_new__impl(StringRef key, ForwardT &&value)
{
BLI_assert(!this->contains(key));
@@ -457,4 +516,4 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
} // namespace BLI
-#endif /* __BLI_STRING_MAP_H__ */
+#endif /* __BLI_STRING_MAP_HH__ */
diff --git a/source/blender/blenlib/BLI_string_ref.h b/source/blender/blenlib/BLI_string_ref.hh
index 2389542bcea..eacc501375a 100644
--- a/source/blender/blenlib/BLI_string_ref.h
+++ b/source/blender/blenlib/BLI_string_ref.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_STRING_REF_H__
-#define __BLI_STRING_REF_H__
+#ifndef __BLI_STRING_REF_HH__
+#define __BLI_STRING_REF_HH__
/** \file
* \ingroup bli
@@ -32,7 +32,7 @@
#include <sstream>
#include <string>
-#include "BLI_array_ref.h"
+#include "BLI_array_ref.hh"
#include "BLI_utildefines.h"
namespace BLI {
@@ -94,12 +94,28 @@ class StringRefBase {
return m_data + m_size;
}
- void copy_to__with_null(char *dst) const
+ void unsafe_copy(char *dst) const
{
memcpy(dst, m_data, m_size);
dst[m_size] = '\0';
}
+ void copy(char *dst, uint dst_size) const
+ {
+ if (m_size < dst_size) {
+ this->unsafe_copy(dst);
+ }
+ else {
+ BLI_assert(false);
+ dst[0] = '\0';
+ }
+ }
+
+ template<uint N> void copy(char (&dst)[N])
+ {
+ this->copy(dst, N);
+ }
+
/**
* Returns true when the string begins with the given prefix. Otherwise false.
*/
@@ -252,4 +268,4 @@ inline StringRef StringRefBase::substr(uint start, uint size) const
} // namespace BLI
-#endif /* __BLI_STRING_REF_H__ */
+#endif /* __BLI_STRING_REF_HH__ */
diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h
index 8c0c9ad99bf..50f8adc20f6 100644
--- a/source/blender/blenlib/BLI_system.h
+++ b/source/blender/blenlib/BLI_system.h
@@ -53,6 +53,10 @@ int BLI_system_memory_max_in_megabytes_int(void);
/* getpid */
#ifdef WIN32
# define BLI_SYSTEM_PID_H <process.h>
+
+/* void* since we really do not want to drag Windows.h in to get the proper typedef. */
+void BLI_windows_handle_exception(void *exception);
+
#else
# define BLI_SYSTEM_PID_H <unistd.h>
#endif
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 898e4be5f92..ee087600a31 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -43,12 +43,9 @@ struct BLI_mempool;
* must be called from the main threads. All other scheduler and pool functions
* are thread-safe. */
-typedef struct TaskScheduler TaskScheduler;
-
-TaskScheduler *BLI_task_scheduler_create(int num_threads);
-void BLI_task_scheduler_free(TaskScheduler *scheduler);
-
-int BLI_task_scheduler_num_threads(TaskScheduler *scheduler);
+void BLI_task_scheduler_init(void);
+void BLI_task_scheduler_exit(void);
+int BLI_task_scheduler_num_threads(void);
/* Task Pool
*
@@ -70,16 +67,14 @@ typedef enum TaskPriority {
} TaskPriority;
typedef struct TaskPool TaskPool;
-typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata, int threadid);
-typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata, int threadid);
-
-TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata, TaskPriority priority);
-TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler,
- void *userdata,
- TaskPriority priority);
-TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler,
- void *userdata,
- TaskPriority priority);
+typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata);
+typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata);
+
+TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority);
+TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority);
+TaskPool *BLI_task_pool_create_suspended(void *userdata, TaskPriority priority);
+TaskPool *BLI_task_pool_create_no_threads(void *userdata);
+TaskPool *BLI_task_pool_create_background_serial(void *userdata, TaskPriority priority);
void BLI_task_pool_free(TaskPool *pool);
void BLI_task_pool_push(TaskPool *pool,
@@ -87,17 +82,9 @@ void BLI_task_pool_push(TaskPool *pool,
void *taskdata,
bool free_taskdata,
TaskFreeFunction freedata);
-void BLI_task_pool_push_from_thread(TaskPool *pool,
- TaskRunFunction run,
- void *taskdata,
- bool free_taskdata,
- TaskFreeFunction freedata,
- int thread_id);
/* work and wait until all tasks are done */
void BLI_task_pool_work_and_wait(TaskPool *pool);
-/* work and wait until all tasks are done, then reset to the initial suspended state */
-void BLI_task_pool_work_wait_and_reset(TaskPool *pool);
/* cancel all tasks, keep worker threads running */
void BLI_task_pool_cancel(TaskPool *pool);
@@ -105,53 +92,29 @@ void BLI_task_pool_cancel(TaskPool *pool);
bool BLI_task_pool_canceled(TaskPool *pool);
/* optional userdata pointer to pass along to run function */
-void *BLI_task_pool_userdata(TaskPool *pool);
+void *BLI_task_pool_user_data(TaskPool *pool);
/* optional mutex to use from run function */
ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
-/* Thread ID of thread that created the task pool. */
-int BLI_task_pool_creator_thread_id(TaskPool *pool);
-
-/* Delayed push, use that to reduce thread overhead by accumulating
- * all new tasks into local queue first and pushing it to scheduler
- * from within a single mutex lock.
- */
-void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id);
-void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id);
-
/* Parallel for routines */
-typedef enum eTaskSchedulingMode {
- /* Task scheduler will divide overall work into equal chunks, scheduling
- * even chunks to all worker threads.
- * Least run time benefit, ideal for cases when each task requires equal
- * amount of compute power.
- */
- TASK_SCHEDULING_STATIC,
- /* Task scheduler will schedule small amount of work to each worker thread.
- * Has more run time overhead, but deals much better with cases when each
- * part of the work requires totally different amount of compute power.
- */
- TASK_SCHEDULING_DYNAMIC,
-} eTaskSchedulingMode;
-
/* Per-thread specific data passed to the callback. */
typedef struct TaskParallelTLS {
- /* Identifier of the thread who this data belongs to. */
- int thread_id;
/* Copy of user-specifier chunk, which is copied from original chunk to all
* worker threads. This is similar to OpenMP's firstprivate.
*/
void *userdata_chunk;
} TaskParallelTLS;
-typedef void (*TaskParallelFinalizeFunc)(void *__restrict userdata,
- void *__restrict userdata_chunk);
-
typedef void (*TaskParallelRangeFunc)(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls);
+typedef void (*TaskParallelReduceFunc)(const void *__restrict userdata,
+ void *__restrict chunk_join,
+ void *__restrict chunk);
+
+typedef void (*TaskParallelFreeFunc)(const void *__restrict userdata, void *__restrict chunk);
typedef struct TaskParallelSettings {
/* Whether caller allows to do threading of the particular range.
@@ -161,8 +124,6 @@ typedef struct TaskParallelSettings {
* is higher than a chunk size. As in, threading will always be performed.
*/
bool use_threading;
- /* Scheduling mode to use for this parallel range invocation. */
- eTaskSchedulingMode scheduling_mode;
/* Each instance of looping chunks will get a copy of this data
* (similar to OpenMP's firstprivate).
*/
@@ -171,7 +132,13 @@ typedef struct TaskParallelSettings {
/* Function called from calling thread once whole range have been
* processed.
*/
- TaskParallelFinalizeFunc func_finalize;
+ /* Function called to join user data chunk into another, to reduce
+ * the result to the original userdata_chunk memory.
+ * The reduce functions should have no side effects, so that they
+ * can be run on any thread. */
+ TaskParallelReduceFunc func_reduce;
+ /* Function called to free data created by TaskParallelRangeFunc. */
+ TaskParallelFreeFunc func_free;
/* Minimum allowed number of range iterators to be handled by a single
* thread. This allows to achieve following:
* - Reduce amount of threading overhead.
@@ -191,19 +158,7 @@ void BLI_task_parallel_range(const int start,
const int stop,
void *userdata,
TaskParallelRangeFunc func,
- TaskParallelSettings *settings);
-
-typedef struct TaskParallelRangePool TaskParallelRangePool;
-struct TaskParallelRangePool *BLI_task_parallel_range_pool_init(
- const struct TaskParallelSettings *settings);
-void BLI_task_parallel_range_pool_push(struct TaskParallelRangePool *range_pool,
- const int start,
- const int stop,
- void *userdata,
- TaskParallelRangeFunc func,
- const struct TaskParallelSettings *settings);
-void BLI_task_parallel_range_pool_work_and_wait(struct TaskParallelRangePool *range_pool);
-void BLI_task_parallel_range_pool_free(struct TaskParallelRangePool *range_pool);
+ const TaskParallelSettings *settings);
/* This data is shared between all tasks, its access needs thread lock or similar protection.
*/
@@ -258,11 +213,14 @@ BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *setti
{
memset(settings, 0, sizeof(*settings));
settings->use_threading = true;
- settings->scheduling_mode = TASK_SCHEDULING_STATIC;
/* Use default heuristic to define actual chunk size. */
settings->min_iter_per_thread = 0;
}
+/* Don't use this, store any thread specific data in tls->userdata_chunk instead.
+ * Ony here for code to be removed. */
+int BLI_task_parallel_thread_id(const TaskParallelTLS *tls);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index c2127c1ec3a..243efedebf9 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -47,8 +47,6 @@ struct TaskScheduler;
void BLI_threadapi_init(void);
void BLI_threadapi_exit(void);
-struct TaskScheduler *BLI_task_scheduler_get(void);
-
void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot);
int BLI_available_threads(struct ListBase *threadbase);
int BLI_threadpool_available_thread_index(struct ListBase *threadbase);
diff --git a/source/blender/blenlib/BLI_timeit.hh b/source/blender/blenlib/BLI_timeit.hh
new file mode 100644
index 00000000000..e9f121ec654
--- /dev/null
+++ b/source/blender/blenlib/BLI_timeit.hh
@@ -0,0 +1,62 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_TIMEIT_HH__
+#define __BLI_TIMEIT_HH__
+
+#include <chrono>
+#include <iostream>
+#include <string>
+
+#include "BLI_sys_types.h"
+
+namespace BLI {
+namespace Timeit {
+
+using Clock = std::chrono::steady_clock;
+using TimePoint = Clock::time_point;
+using Nanoseconds = std::chrono::nanoseconds;
+
+void print_duration(Nanoseconds duration);
+
+class ScopedTimer {
+ private:
+ std::string m_name;
+ TimePoint m_start;
+
+ public:
+ ScopedTimer(std::string name) : m_name(std::move(name))
+ {
+ m_start = Clock::now();
+ }
+
+ ~ScopedTimer()
+ {
+ TimePoint end = Clock::now();
+ Nanoseconds duration = end - m_start;
+
+ std::cout << "Timer '" << m_name << "' took ";
+ print_duration(duration);
+ std::cout << '\n';
+ }
+};
+
+} // namespace Timeit
+} // namespace BLI
+
+#define SCOPED_TIMER(name) BLI::Timeit::ScopedTimer scoped_timer(name)
+
+#endif /* __BLI_TIMEIT_HH__ */
diff --git a/source/blender/blenlib/BLI_utility_mixins.h b/source/blender/blenlib/BLI_utility_mixins.hh
index ce7a4ce094a..441575f9111 100644
--- a/source/blender/blenlib/BLI_utility_mixins.h
+++ b/source/blender/blenlib/BLI_utility_mixins.hh
@@ -18,8 +18,8 @@
* \ingroup bli
*/
-#ifndef __BLI_UTILITY_MIXINS_H__
-#define __BLI_UTILITY_MIXINS_H__
+#ifndef __BLI_UTILITY_MIXINS_HH__
+#define __BLI_UTILITY_MIXINS_HH__
namespace BLI {
@@ -49,4 +49,4 @@ class NonMovable {
} // namespace BLI
-#endif /* __BLI_UTILITY_MIXINS_H__ */
+#endif /* __BLI_UTILITY_MIXINS_HH__ */
diff --git a/source/blender/blenlib/BLI_vector.h b/source/blender/blenlib/BLI_vector.hh
index 6a708759d0e..49cf41c2005 100644
--- a/source/blender/blenlib/BLI_vector.h
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_VECTOR_H__
-#define __BLI_VECTOR_H__
+#ifndef __BLI_VECTOR_HH__
+#define __BLI_VECTOR_HH__
/** \file
* \ingroup bli
@@ -31,25 +31,26 @@
#include <iostream>
#include <memory>
-#include "BLI_allocator.h"
-#include "BLI_array_ref.h"
-#include "BLI_index_range.h"
-#include "BLI_listbase_wrapper.h"
+#include "BLI_allocator.hh"
+#include "BLI_array_ref.hh"
+#include "BLI_index_range.hh"
+#include "BLI_listbase_wrapper.hh"
#include "BLI_math_base.h"
-#include "BLI_memory_utils_cxx.h"
+#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
namespace BLI {
-template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Vector {
+template<typename T, uint InlineBufferCapacity = 4, typename Allocator = GuardedAllocator>
+class Vector {
private:
T *m_begin;
T *m_end;
T *m_capacity_end;
Allocator m_allocator;
- AlignedBuffer<sizeof(T) * N, alignof(T)> m_small_buffer;
+ AlignedBuffer<(uint)sizeof(T) * InlineBufferCapacity, (uint)alignof(T)> m_small_buffer;
#ifndef NDEBUG
/* Storing size in debug builds, because it makes debugging much easier sometimes. */
@@ -70,7 +71,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
{
m_begin = this->small_buffer();
m_end = m_begin;
- m_capacity_end = m_begin + N;
+ m_capacity_end = m_begin + InlineBufferCapacity;
UPDATE_VECTOR_SIZE(this);
}
@@ -130,20 +131,17 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
/**
* Create a vector from a ListBase.
*/
- Vector(ListBase &values, bool intrusive_next_and_prev_pointers) : Vector()
+ Vector(ListBase &values) : Vector()
{
- BLI_assert(intrusive_next_and_prev_pointers);
- if (intrusive_next_and_prev_pointers) {
- for (T value : IntrusiveListBaseWrapper<typename std::remove_pointer<T>::type>(values)) {
- this->append(value);
- }
+ for (T value : ListBaseWrapper<typename std::remove_pointer<T>::type>(values)) {
+ this->append(value);
}
}
/**
* Create a copy of another vector.
* The other vector will not be changed.
- * If the other vector has less than N elements, no allocation will be made.
+ * If the other vector has less than InlineBufferCapacity elements, no allocation will be made.
*/
Vector(const Vector &other) : m_allocator(other.m_allocator)
{
@@ -167,11 +165,11 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
uint size = other.size();
if (other.is_small()) {
- if (size <= N) {
+ if (size <= InlineBufferCapacity) {
/* Copy between inline buffers. */
m_begin = this->small_buffer();
m_end = m_begin + size;
- m_capacity_end = m_begin + N;
+ m_capacity_end = m_begin + InlineBufferCapacity;
uninitialized_relocate_n(other.m_begin, size, m_begin);
}
else {
@@ -286,7 +284,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
m_begin = this->small_buffer();
m_end = m_begin;
- m_capacity_end = m_begin + N;
+ m_capacity_end = m_begin + InlineBufferCapacity;
UPDATE_VECTOR_SIZE(this);
}
@@ -429,7 +427,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
/**
* Returns true when the vector contains no elements, otherwise false.
*/
- bool empty() const
+ bool is_empty() const
{
return m_begin == m_end;
}
@@ -440,7 +438,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
*/
void remove_last()
{
- BLI_assert(!this->empty());
+ BLI_assert(!this->is_empty());
m_end--;
destruct(m_end);
UPDATE_VECTOR_SIZE(this);
@@ -451,7 +449,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
*/
T pop_last()
{
- BLI_assert(!this->empty());
+ BLI_assert(!this->is_empty());
m_end--;
T value = std::move(*m_end);
destruct(m_end);
@@ -581,7 +579,8 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
std::cout << "Small Vector at " << (void *)this << ":" << std::endl;
std::cout << " Elements: " << this->size() << std::endl;
std::cout << " Capacity: " << (m_capacity_end - m_begin) << std::endl;
- std::cout << " Small Elements: " << N << " Size on Stack: " << sizeof(*this) << std::endl;
+ std::cout << " Small Elements: " << InlineBufferCapacity
+ << " Size on Stack: " << sizeof(*this) << std::endl;
}
private:
@@ -637,9 +636,9 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
uint size = other.size();
uint capacity = size;
- if (size <= N) {
+ if (size <= InlineBufferCapacity) {
m_begin = this->small_buffer();
- capacity = N;
+ capacity = InlineBufferCapacity;
}
else {
m_begin = (T *)m_allocator.allocate_aligned(
@@ -661,8 +660,9 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
* Use when the vector is used in the local scope of a function. It has a larger inline storage by
* default to make allocations less likely.
*/
-template<typename T, uint N = 20> using ScopedVector = Vector<T, N, GuardedAllocator>;
+template<typename T, uint InlineBufferCapacity = 20>
+using ScopedVector = Vector<T, InlineBufferCapacity, GuardedAllocator>;
} /* namespace BLI */
-#endif /* __BLI_VECTOR_H__ */
+#endif /* __BLI_VECTOR_HH__ */
diff --git a/source/blender/blenlib/BLI_vector_set.h b/source/blender/blenlib/BLI_vector_set.hh
index 99d955c60d8..9f887513816 100644
--- a/source/blender/blenlib/BLI_vector_set.h
+++ b/source/blender/blenlib/BLI_vector_set.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_VECTOR_SET_H__
-#define __BLI_VECTOR_SET_H__
+#ifndef __BLI_VECTOR_SET_HH__
+#define __BLI_VECTOR_SET_HH__
/** \file
* \ingroup bli
@@ -25,9 +25,9 @@
* no deletes. The expected time to check if a value is in the VectorSet is O(1).
*/
-#include "BLI_hash_cxx.h"
-#include "BLI_open_addressing.h"
-#include "BLI_vector.h"
+#include "BLI_hash.hh"
+#include "BLI_open_addressing.hh"
+#include "BLI_vector.hh"
namespace BLI {
@@ -76,7 +76,7 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
return m_value == IS_DUMMY;
}
- bool has_value(const T &value, const Vector<T> &elements) const
+ bool has_value(const T &value, const T *elements) const
{
return this->is_set() && elements[this->index()] == value;
}
@@ -112,12 +112,14 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
using ArrayType = OpenAddressingArray<Slot, 4, Allocator>;
ArrayType m_array;
- Vector<T, 4, Allocator> m_elements;
+
+ /* The capacity of the array should always be at least m_array.slots_usable(). */
+ T *m_elements = nullptr;
public:
VectorSet()
{
- BLI_assert(m_array.slots_usable() <= m_elements.capacity());
+ m_elements = this->allocate_elements_array(m_array.slots_usable());
}
VectorSet(ArrayRef<T> values) : VectorSet()
@@ -135,6 +137,43 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
this->add_multiple(values);
}
+ VectorSet(const VectorSet &other) : m_array(other.m_array)
+ {
+ m_elements = this->allocate_elements_array(m_array.slots_usable());
+ copy_n(other.m_elements, m_array.slots_set(), m_elements);
+ }
+
+ VectorSet(VectorSet &&other) : m_array(std::move(other.m_array)), m_elements(other.m_elements)
+ {
+ other.m_elements = other.allocate_elements_array(other.m_array.slots_usable());
+ }
+
+ ~VectorSet()
+ {
+ destruct_n(m_elements, this->size());
+ this->deallocate_elements_array(m_elements);
+ }
+
+ VectorSet &operator=(const VectorSet &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ this->~VectorSet();
+ new (this) VectorSet(other);
+ return *this;
+ }
+
+ VectorSet &operator=(VectorSet &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ this->~VectorSet();
+ new (this) VectorSet(std::move(other));
+ return *this;
+ }
+
/**
* Allocate memory such that at least min_usable_slots can be added without having to grow again.
*/
@@ -203,17 +242,17 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
BLI_assert(this->contains(value));
ITER_SLOTS_BEGIN (value, m_array, , slot) {
if (slot.has_value(value, m_elements)) {
- uint old_index = m_elements.size() - 1;
+ uint old_index = this->size() - 1;
uint new_index = slot.index();
- m_elements.remove_and_reorder(new_index);
+ if (new_index < old_index) {
+ m_elements[new_index] = std::move(m_elements[old_index]);
+ this->update_slot_index(m_elements[new_index], old_index, new_index);
+ }
+
+ destruct(m_elements + old_index);
slot.set_dummy();
m_array.update__set_to_dummy();
-
- if (old_index != new_index) {
- T &moved_value = m_elements[new_index];
- this->update_slot_index(moved_value, old_index, new_index);
- }
return;
}
}
@@ -226,11 +265,12 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
T pop()
{
BLI_assert(this->size() > 0);
- T value = m_elements.pop_last();
- uint old_index = m_elements.size();
+ uint index_to_pop = this->size() - 1;
+ T value = std::move(m_elements[index_to_pop]);
+ destruct(m_elements + index_to_pop);
ITER_SLOTS_BEGIN (value, m_array, , slot) {
- if (slot.has_index(old_index)) {
+ if (slot.has_index(index_to_pop)) {
slot.set_dummy();
m_array.update__set_to_dummy();
return value;
@@ -277,18 +317,24 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
return m_array.slots_set();
}
+ bool is_empty() const
+ {
+ return this->size() == 0;
+ }
+
const T *begin() const
{
- return m_elements.begin();
+ return m_elements;
}
const T *end() const
{
- return m_elements.end();
+ return m_elements + this->size();
}
const T &operator[](uint index) const
{
+ BLI_assert(index <= this->size());
return m_elements[index];
}
@@ -299,7 +345,7 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
operator ArrayRef<T>() const
{
- return m_elements;
+ return ArrayRef<T>(m_elements, this->size());
}
void print_stats() const
@@ -326,9 +372,9 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
template<typename ForwardT> void add_new_in_slot(Slot &slot, ForwardT &&value)
{
- uint index = m_elements.size();
+ uint index = this->size();
slot.set_index(index);
- m_elements.append_unchecked(std::forward<ForwardT>(value));
+ new (m_elements + index) T(std::forward<ForwardT>(value));
m_array.update__empty_to_set();
}
@@ -341,14 +387,20 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
BLI_NOINLINE void grow(uint min_usable_slots)
{
+ uint size = this->size();
+
ArrayType new_array = m_array.init_reserved(min_usable_slots);
+ T *new_elements = this->allocate_elements_array(new_array.slots_usable());
- for (uint i = 0; i < m_elements.size(); i++) {
+ for (uint i : IndexRange(size)) {
this->add_after_grow(i, new_array);
}
+ uninitialized_relocate_n(m_elements, size, new_elements);
+ this->deallocate_elements_array(m_elements);
+
m_array = std::move(new_array);
- m_elements.reserve(m_array.slots_usable());
+ m_elements = new_elements;
}
void add_after_grow(uint index, ArrayType &new_array)
@@ -365,15 +417,15 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
float compute_average_collisions() const
{
- if (m_elements.size() == 0) {
+ if (this->size() == 0) {
return 0.0f;
}
uint collisions_sum = 0;
- for (const T &value : m_elements) {
+ for (const T &value : this->as_ref()) {
collisions_sum += this->count_collisions(value);
}
- return (float)collisions_sum / (float)m_elements.size();
+ return (float)collisions_sum / (float)this->size();
}
uint count_collisions(const T &value) const
@@ -415,6 +467,16 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
}
ITER_SLOTS_END;
}
+
+ T *allocate_elements_array(uint size)
+ {
+ return (T *)m_array.allocator().allocate_aligned((uint)sizeof(T) * size, alignof(T), __func__);
+ }
+
+ void deallocate_elements_array(T *elements)
+ {
+ m_array.allocator().deallocate(elements);
+ }
};
#undef ITER_SLOTS_BEGIN
@@ -422,4 +484,4 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
} // namespace BLI
-#endif /* __BLI_VECTOR_SET_H__ */
+#endif /* __BLI_VECTOR_SET_HH__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index bdfe3dd4747..d3bfb553329 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
intern/buffer.c
intern/convexhull_2d.c
intern/delaunay_2d.c
+ intern/dot_export.cc
intern/dynlib.c
intern/easing.c
intern/edgehash.c
@@ -118,11 +119,14 @@ set(SRC
intern/string_utf8.c
intern/string_utils.c
intern/system.c
- intern/task_pool.cc
intern/task_iterator.c
+ intern/task_pool.cc
+ intern/task_range.cc
+ intern/task_scheduler.cc
intern/threads.c
intern/time.c
intern/timecode.c
+ intern/timeit.cc
intern/uvproject.c
intern/voronoi_2d.c
intern/voxel.c
@@ -136,11 +140,11 @@ set(SRC
BLI_alloca.h
- BLI_allocator.h
+ BLI_allocator.hh
BLI_args.h
BLI_array.h
- BLI_array_cxx.h
- BLI_array_ref.h
+ BLI_array.hh
+ BLI_array_ref.hh
BLI_array_store.h
BLI_array_store_utils.h
BLI_array_utils.h
@@ -151,6 +155,7 @@ set(SRC
BLI_blenlib.h
BLI_boxpack_2d.h
BLI_buffer.h
+ BLI_color.hh
BLI_compiler_attrs.h
BLI_compiler_compat.h
BLI_compiler_typecheck.h
@@ -159,6 +164,8 @@ set(SRC
BLI_delaunay_2d.h
BLI_dial_2d.h
BLI_dlrbTree.h
+ BLI_dot_export.hh
+ BLI_dot_export_attribute_enums.hh
BLI_dynlib.h
BLI_dynstr.h
BLI_easing.h
@@ -168,17 +175,20 @@ set(SRC
BLI_expr_pylike_eval.h
BLI_fileops.h
BLI_fileops_types.h
+ BLI_float2.hh
+ BLI_float3.hh
+ BLI_float4x4.hh
BLI_fnmatch.h
BLI_ghash.h
BLI_gsqueue.h
BLI_hash.h
- BLI_hash_cxx.h
+ BLI_hash.hh
BLI_hash_md5.h
BLI_hash_mm2a.h
BLI_hash_mm3.h
BLI_heap.h
BLI_heap_simple.h
- BLI_index_range.h
+ BLI_index_range.hh
BLI_iterator.h
BLI_jitter_2d.h
BLI_kdopbvh.h
@@ -190,8 +200,8 @@ set(SRC
BLI_linklist_lockfree.h
BLI_linklist_stack.h
BLI_listbase.h
- BLI_listbase_wrapper.h
- BLI_map.h
+ BLI_listbase_wrapper.hh
+ BLI_map.hh
BLI_math.h
BLI_math_base.h
BLI_math_bits.h
@@ -209,11 +219,11 @@ set(SRC
BLI_memblock.h
BLI_memiter.h
BLI_memory_utils.h
- BLI_memory_utils_cxx.h
+ BLI_memory_utils.hh
BLI_mempool.h
BLI_noise.h
- BLI_open_addressing.h
- BLI_optional.h
+ BLI_open_addressing.hh
+ BLI_optional.hh
BLI_path_util.h
BLI_polyfill_2d.h
BLI_polyfill_2d_beautify.h
@@ -221,17 +231,17 @@ set(SRC
BLI_rand.h
BLI_rect.h
BLI_scanfill.h
- BLI_set.h
+ BLI_set.hh
BLI_smallhash.h
BLI_sort.h
BLI_sort_utils.h
BLI_stack.h
- BLI_stack_cxx.h
+ BLI_stack.hh
BLI_strict_flags.h
BLI_string.h
BLI_string_cursor_utf8.h
- BLI_string_map.h
- BLI_string_ref.h
+ BLI_string_map.hh
+ BLI_string_ref.hh
BLI_string_utf8.h
BLI_string_utils.h
BLI_sys_types.h
@@ -239,15 +249,16 @@ set(SRC
BLI_task.h
BLI_threads.h
BLI_timecode.h
+ BLI_timeit.hh
BLI_timer.h
BLI_utildefines.h
BLI_utildefines_iter.h
BLI_utildefines_stack.h
BLI_utildefines_variadic.h
- BLI_utility_mixins.h
+ BLI_utility_mixins.hh
BLI_uvproject.h
- BLI_vector.h
- BLI_vector_set.h
+ BLI_vector.hh
+ BLI_vector_set.hh
BLI_vfontdata.h
BLI_voronoi_2d.h
BLI_voxel.h
@@ -269,6 +280,14 @@ if(WITH_MEM_VALGRIND)
add_definitions(-DWITH_MEM_VALGRIND)
endif()
+if(WITH_TBB)
+ add_definitions(-DWITH_TBB)
+
+ list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+ )
+endif()
+
if(WIN32)
list(APPEND INC
../../../intern/utfconv
@@ -276,6 +295,9 @@ if(WIN32)
list(APPEND LIB
bf_intern_utfconv
)
+ list(APPEND SRC
+ intern/system_win32.c
+ )
endif()
diff --git a/source/blender/blenlib/intern/BLI_index_range.cc b/source/blender/blenlib/intern/BLI_index_range.cc
index 90eb4e4a89c..fefb6e6598e 100644
--- a/source/blender/blenlib/intern/BLI_index_range.cc
+++ b/source/blender/blenlib/intern/BLI_index_range.cc
@@ -17,10 +17,10 @@
#include <atomic>
#include <mutex>
-#include "BLI_array_cxx.h"
-#include "BLI_array_ref.h"
-#include "BLI_index_range.h"
-#include "BLI_vector.h"
+#include "BLI_array.hh"
+#include "BLI_array_ref.hh"
+#include "BLI_index_range.hh"
+#include "BLI_vector.hh"
namespace BLI {
diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c
index 836292e0c88..4e0cd3a78dc 100644
--- a/source/blender/blenlib/intern/delaunay_2d.c
+++ b/source/blender/blenlib/intern/delaunay_2d.c
@@ -1264,6 +1264,7 @@ static void fill_crossdata_for_intersect(CDT_state *cdt,
se_vcva = t->next->next;
BLI_assert(se_vcva->vert == vc && se_vcva->next->vert == va);
BLI_assert(se_vcvb->vert == vc && se_vcvb->next->vert == vb);
+ UNUSED_VARS_NDEBUG(vc);
isect = isect_seg_seg_v2_lambda_mu_db(va->co, vb->co, curco, v2->co, &lambda, &mu);
#ifdef DEBUG_CDT
if (dbg_level > 0) {
diff --git a/source/blender/blenlib/intern/dot_export.cc b/source/blender/blenlib/intern/dot_export.cc
new file mode 100644
index 00000000000..96de4056fc5
--- /dev/null
+++ b/source/blender/blenlib/intern/dot_export.cc
@@ -0,0 +1,305 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <iomanip>
+
+#include "BLI_dot_export.hh"
+
+namespace BLI {
+namespace DotExport {
+
+/* Graph Building
+ ************************************************/
+
+Node &Graph::new_node(StringRef label)
+{
+ Node *node = new Node(*this);
+ m_nodes.append(std::unique_ptr<Node>(node));
+ m_top_level_nodes.add_new(node);
+ node->set_attribute("label", label);
+ return *node;
+}
+
+Cluster &Graph::new_cluster(StringRef label)
+{
+ Cluster *cluster = new Cluster(*this);
+ m_clusters.append(std::unique_ptr<Cluster>(cluster));
+ m_top_level_clusters.add_new(cluster);
+ cluster->set_attribute("label", label);
+ return *cluster;
+}
+
+UndirectedEdge &UndirectedGraph::new_edge(NodePort a, NodePort b)
+{
+ UndirectedEdge *edge = new UndirectedEdge(a, b);
+ m_edges.append(std::unique_ptr<UndirectedEdge>(edge));
+ return *edge;
+}
+
+DirectedEdge &DirectedGraph::new_edge(NodePort from, NodePort to)
+{
+ DirectedEdge *edge = new DirectedEdge(from, to);
+ m_edges.append(std::unique_ptr<DirectedEdge>(edge));
+ return *edge;
+}
+
+void Cluster::set_parent_cluster(Cluster *new_parent)
+{
+ if (m_parent == new_parent) {
+ return;
+ }
+ else if (m_parent == nullptr) {
+ m_graph.m_top_level_clusters.remove(this);
+ new_parent->m_children.add_new(this);
+ }
+ else if (new_parent == nullptr) {
+ m_parent->m_children.remove(this);
+ m_graph.m_top_level_clusters.add_new(this);
+ }
+ else {
+ m_parent->m_children.remove(this);
+ new_parent->m_children.add_new(this);
+ }
+ m_parent = new_parent;
+}
+
+void Node::set_parent_cluster(Cluster *cluster)
+{
+ if (m_cluster == cluster) {
+ return;
+ }
+ else if (m_cluster == nullptr) {
+ m_graph.m_top_level_nodes.remove(this);
+ cluster->m_nodes.add_new(this);
+ }
+ else if (cluster == nullptr) {
+ m_cluster->m_nodes.remove(this);
+ m_graph.m_top_level_nodes.add_new(this);
+ }
+ else {
+ m_cluster->m_nodes.remove(this);
+ cluster->m_nodes.add_new(this);
+ }
+ m_cluster = cluster;
+}
+
+/* Utility methods
+ **********************************************/
+
+void Graph::set_random_cluster_bgcolors()
+{
+ for (Cluster *cluster : m_top_level_clusters) {
+ cluster->set_random_cluster_bgcolors();
+ }
+}
+
+void Cluster::set_random_cluster_bgcolors()
+{
+ float hue = rand() / (float)RAND_MAX;
+ float staturation = 0.3f;
+ float value = 0.8f;
+ this->set_attribute("bgcolor", color_attr_from_hsv(hue, staturation, value));
+
+ for (Cluster *cluster : m_children) {
+ cluster->set_random_cluster_bgcolors();
+ }
+}
+
+/* Dot Generation
+ **********************************************/
+
+std::string DirectedGraph::to_dot_string() const
+{
+ std::stringstream ss;
+ ss << "digraph {\n";
+ this->export__declare_nodes_and_clusters(ss);
+ ss << "\n";
+
+ for (const std::unique_ptr<DirectedEdge> &edge : m_edges) {
+ edge->export__as_edge_statement(ss);
+ ss << "\n";
+ }
+
+ ss << "}\n";
+ return ss.str();
+}
+
+std::string UndirectedGraph::to_dot_string() const
+{
+ std::stringstream ss;
+ ss << "graph {\n";
+ this->export__declare_nodes_and_clusters(ss);
+ ss << "\n";
+
+ for (const std::unique_ptr<UndirectedEdge> &edge : m_edges) {
+ edge->export__as_edge_statement(ss);
+ ss << "\n";
+ }
+
+ ss << "}\n";
+ return ss.str();
+}
+
+void Graph::export__declare_nodes_and_clusters(std::stringstream &ss) const
+{
+ ss << "graph ";
+ m_attributes.export__as_bracket_list(ss);
+ ss << "\n\n";
+
+ for (Node *node : m_top_level_nodes) {
+ node->export__as_declaration(ss);
+ }
+
+ for (Cluster *cluster : m_top_level_clusters) {
+ cluster->export__declare_nodes_and_clusters(ss);
+ }
+}
+
+void Cluster::export__declare_nodes_and_clusters(std::stringstream &ss) const
+{
+ ss << "subgraph cluster_" << (uintptr_t)this << " {\n";
+
+ ss << "graph ";
+ m_attributes.export__as_bracket_list(ss);
+ ss << "\n\n";
+
+ for (Node *node : m_nodes) {
+ node->export__as_declaration(ss);
+ }
+
+ for (Cluster *cluster : m_children) {
+ cluster->export__declare_nodes_and_clusters(ss);
+ }
+
+ ss << "}\n";
+}
+
+void DirectedEdge::export__as_edge_statement(std::stringstream &ss) const
+{
+ m_a.to_dot_string(ss);
+ ss << " -> ";
+ m_b.to_dot_string(ss);
+ ss << " ";
+ m_attributes.export__as_bracket_list(ss);
+}
+
+void UndirectedEdge::export__as_edge_statement(std::stringstream &ss) const
+{
+ m_a.to_dot_string(ss);
+ ss << " -- ";
+ m_b.to_dot_string(ss);
+ ss << " ";
+ m_attributes.export__as_bracket_list(ss);
+}
+
+void AttributeList::export__as_bracket_list(std::stringstream &ss) const
+{
+ ss << "[";
+ m_attributes.foreach_item([&](StringRef key, StringRef value) {
+ if (StringRef(value).startswith("<")) {
+ /* Don't draw the quotes, this is an html-like value. */
+ ss << key << "=" << value << ", ";
+ }
+ else {
+ ss << key << "=\"" << value << "\", ";
+ }
+ });
+ ss << "]";
+}
+
+void Node::export__as_id(std::stringstream &ss) const
+{
+ ss << '"' << (uintptr_t)this << '"';
+}
+
+void Node::export__as_declaration(std::stringstream &ss) const
+{
+ this->export__as_id(ss);
+ ss << " ";
+ m_attributes.export__as_bracket_list(ss);
+ ss << "\n";
+}
+
+void NodePort::to_dot_string(std::stringstream &ss) const
+{
+ m_node->export__as_id(ss);
+ if (m_port_name.has_value()) {
+ ss << ":" << m_port_name.value();
+ }
+}
+
+std::string color_attr_from_hsv(float h, float s, float v)
+{
+ std::stringstream ss;
+ ss << std::setprecision(4) << h << ' ' << s << ' ' << v;
+ return ss.str();
+}
+
+NodeWithSocketsRef::NodeWithSocketsRef(Node &node,
+ StringRef name,
+ ArrayRef<std::string> input_names,
+ ArrayRef<std::string> output_names)
+ : m_node(&node)
+{
+ std::stringstream ss;
+
+ ss << "<<table border=\"0\" cellspacing=\"3\">";
+
+ /* Header */
+ ss << "<tr><td colspan=\"3\" align=\"center\"><b>";
+ ss << ((name.size() == 0) ? "No Name" : name);
+ ss << "</b></td></tr>";
+
+ /* Sockets */
+ uint socket_max_amount = std::max(input_names.size(), output_names.size());
+ for (uint i = 0; i < socket_max_amount; i++) {
+ ss << "<tr>";
+ if (i < input_names.size()) {
+ StringRef name = input_names[i];
+ if (name.size() == 0) {
+ name = "No Name";
+ }
+ ss << "<td align=\"left\" port=\"in" << i << "\">";
+ ss << name;
+ ss << "</td>";
+ }
+ else {
+ ss << "<td></td>";
+ }
+ ss << "<td></td>";
+ if (i < output_names.size()) {
+ StringRef name = output_names[i];
+ if (name.size() == 0) {
+ name = "No Name";
+ }
+ ss << "<td align=\"right\" port=\"out" << i << "\">";
+ ss << name;
+ ss << "</td>";
+ }
+ else {
+ ss << "<td></td>";
+ }
+ ss << "</tr>";
+ }
+
+ ss << "</table>>";
+
+ m_node->set_attribute("label", ss.str());
+ m_node->set_shape(Attr_shape::Rectangle);
+}
+
+} // namespace DotExport
+} // namespace BLI
diff --git a/source/blender/blenlib/intern/lasso_2d.c b/source/blender/blenlib/intern/lasso_2d.c
index f1e9b1e655f..a01adf4fa6a 100644
--- a/source/blender/blenlib/intern/lasso_2d.c
+++ b/source/blender/blenlib/intern/lasso_2d.c
@@ -28,47 +28,47 @@
#include "BLI_lasso_2d.h" /* own include */
-void BLI_lasso_boundbox(rcti *rect, const int mcords[][2], const unsigned int moves)
+void BLI_lasso_boundbox(rcti *rect, const int mcoords[][2], const unsigned int mcoords_len)
{
unsigned int a;
- rect->xmin = rect->xmax = mcords[0][0];
- rect->ymin = rect->ymax = mcords[0][1];
+ rect->xmin = rect->xmax = mcoords[0][0];
+ rect->ymin = rect->ymax = mcoords[0][1];
- for (a = 1; a < moves; a++) {
- if (mcords[a][0] < rect->xmin) {
- rect->xmin = mcords[a][0];
+ for (a = 1; a < mcoords_len; a++) {
+ if (mcoords[a][0] < rect->xmin) {
+ rect->xmin = mcoords[a][0];
}
- else if (mcords[a][0] > rect->xmax) {
- rect->xmax = mcords[a][0];
+ else if (mcoords[a][0] > rect->xmax) {
+ rect->xmax = mcoords[a][0];
}
- if (mcords[a][1] < rect->ymin) {
- rect->ymin = mcords[a][1];
+ if (mcoords[a][1] < rect->ymin) {
+ rect->ymin = mcoords[a][1];
}
- else if (mcords[a][1] > rect->ymax) {
- rect->ymax = mcords[a][1];
+ else if (mcoords[a][1] > rect->ymax) {
+ rect->ymax = mcoords[a][1];
}
}
}
-bool BLI_lasso_is_point_inside(const int mcords[][2],
- const unsigned int moves,
+bool BLI_lasso_is_point_inside(const int mcoords[][2],
+ const unsigned int mcoords_len,
const int sx,
const int sy,
const int error_value)
{
- if (sx == error_value || moves == 0) {
+ if (sx == error_value || mcoords_len == 0) {
return false;
}
else {
int pt[2] = {sx, sy};
- return isect_point_poly_v2_int(pt, mcords, moves, true);
+ return isect_point_poly_v2_int(pt, mcoords, mcoords_len, true);
}
}
/* edge version for lasso select. we assume boundbox check was done */
-bool BLI_lasso_is_edge_inside(const int mcords[][2],
- const unsigned int moves,
+bool BLI_lasso_is_edge_inside(const int mcoords[][2],
+ const unsigned int mcoords_len,
int x0,
int y0,
int x1,
@@ -76,27 +76,27 @@ bool BLI_lasso_is_edge_inside(const int mcords[][2],
const int error_value)
{
- if (x0 == error_value || x1 == error_value || moves == 0) {
+ if (x0 == error_value || x1 == error_value || mcoords_len == 0) {
return false;
}
const int v1[2] = {x0, y0}, v2[2] = {x1, y1};
/* check points in lasso */
- if (BLI_lasso_is_point_inside(mcords, moves, v1[0], v1[1], error_value)) {
+ if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v1[0], v1[1], error_value)) {
return true;
}
- if (BLI_lasso_is_point_inside(mcords, moves, v2[0], v2[1], error_value)) {
+ if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v2[0], v2[1], error_value)) {
return true;
}
/* no points in lasso, so we have to intersect with lasso edge */
- if (isect_seg_seg_v2_int(mcords[0], mcords[moves - 1], v1, v2) > 0) {
+ if (isect_seg_seg_v2_int(mcoords[0], mcoords[mcoords_len - 1], v1, v2) > 0) {
return true;
}
- for (unsigned int a = 0; a < moves - 1; a++) {
- if (isect_seg_seg_v2_int(mcords[a], mcords[a + 1], v1, v2) > 0) {
+ for (unsigned int a = 0; a < mcoords_len - 1; a++) {
+ if (isect_seg_seg_v2_int(mcoords[a], mcoords[a + 1], v1, v2) > 0) {
return true;
}
}
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index d2c55233653..ca405907bdd 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -123,6 +123,27 @@ MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
r[3] = a[3];
}
+MINLINE void copy_v2_uchar(unsigned char r[2], const unsigned char a)
+{
+ r[0] = a;
+ r[1] = a;
+}
+
+MINLINE void copy_v3_uchar(unsigned char r[3], const unsigned char a)
+{
+ r[0] = a;
+ r[1] = a;
+ r[2] = a;
+}
+
+MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a)
+{
+ r[0] = a;
+ r[1] = a;
+ r[2] = a;
+ r[3] = a;
+}
+
/* char */
MINLINE void copy_v2_v2_char(char r[2], const char a[2])
{
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 7d9ed2598a6..53db49aa59c 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -32,11 +32,8 @@
/* for backtrace and gethostname/GetComputerName */
#if defined(WIN32)
# include <intrin.h>
-# include <windows.h>
-# pragma warning(push)
-# pragma warning(disable : 4091)
-# include <dbghelp.h>
-# pragma warning(pop)
+
+# include "BLI_winstuff.h"
#else
# include <execinfo.h>
# include <unistd.h>
@@ -74,6 +71,8 @@ int BLI_cpu_support_sse2(void)
#endif
}
+/* Windows stackwalk lives in system_win32.c */
+#if !defined(_MSC_VER)
/**
* Write a backtrace into a file for systems which support it.
*/
@@ -81,9 +80,9 @@ void BLI_system_backtrace(FILE *fp)
{
/* ------------- */
/* Linux / Apple */
-#if defined(__linux__) || defined(__APPLE__)
+# if defined(__linux__) || defined(__APPLE__)
-# define SIZE 100
+# define SIZE 100
void *buffer[SIZE];
int nptrs;
char **strings;
@@ -98,48 +97,15 @@ void BLI_system_backtrace(FILE *fp)
}
free(strings);
-# undef SIZE
-
- /* -------- */
- /* Windows */
-#elif defined(_MSC_VER)
-
-# ifndef NDEBUG
-# define MAXSYMBOL 256
-# define SIZE 100
- unsigned short i;
- void *stack[SIZE];
- unsigned short nframes;
- SYMBOL_INFO *symbolinfo;
- HANDLE process;
-
- process = GetCurrentProcess();
-
- SymInitialize(process, NULL, TRUE);
-
- nframes = CaptureStackBackTrace(0, SIZE, stack, NULL);
- symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + MAXSYMBOL * sizeof(char), "crash Symbol table");
- symbolinfo->MaxNameLen = MAXSYMBOL - 1;
- symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO);
-
- for (i = 0; i < nframes; i++) {
- SymFromAddr(process, (DWORD64)(stack[i]), 0, symbolinfo);
-
- fprintf(fp, "%u: %s - 0x%0llX\n", nframes - i - 1, symbolinfo->Name, symbolinfo->Address);
- }
-
- MEM_freeN(symbolinfo);
-# undef MAXSYMBOL
# undef SIZE
+
# else
- fprintf(fp, "Crash backtrace not supported on release builds\n");
-# endif /* NDEBUG */
-#else /* _MSC_VER */
/* ------------------ */
/* non msvc/osx/linux */
(void)fp;
-#endif
+# endif
}
+#endif
/* end BLI_system_backtrace */
/* NOTE: The code for CPU brand string is adopted from Cycles. */
diff --git a/source/blender/blenlib/intern/system_win32.c b/source/blender/blenlib/intern/system_win32.c
new file mode 100644
index 00000000000..4fea47386ea
--- /dev/null
+++ b/source/blender/blenlib/intern/system_win32.c
@@ -0,0 +1,378 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ */
+#include <Windows.h>
+#include <stdio.h>
+
+#include <dbghelp.h>
+#include <shlwapi.h>
+#include <tlhelp32.h>
+
+#include "BLI_string.h"
+
+#include "MEM_guardedalloc.h"
+
+static EXCEPTION_POINTERS *current_exception;
+
+static const char *bli_windows_get_exception_description(const DWORD exceptioncode)
+{
+ switch (exceptioncode) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ return "EXCEPTION_ACCESS_VIOLATION";
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
+ case EXCEPTION_BREAKPOINT:
+ return "EXCEPTION_BREAKPOINT";
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ return "EXCEPTION_DATATYPE_MISALIGNMENT";
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ return "EXCEPTION_FLT_DENORMAL_OPERAND";
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ return "EXCEPTION_FLT_INEXACT_RESULT";
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ return "EXCEPTION_FLT_INVALID_OPERATION";
+ case EXCEPTION_FLT_OVERFLOW:
+ return "EXCEPTION_FLT_OVERFLOW";
+ case EXCEPTION_FLT_STACK_CHECK:
+ return "EXCEPTION_FLT_STACK_CHECK";
+ case EXCEPTION_FLT_UNDERFLOW:
+ return "EXCEPTION_FLT_UNDERFLOW";
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ return "EXCEPTION_ILLEGAL_INSTRUCTION";
+ case EXCEPTION_IN_PAGE_ERROR:
+ return "EXCEPTION_IN_PAGE_ERROR";
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ return "EXCEPTION_INT_DIVIDE_BY_ZERO";
+ case EXCEPTION_INT_OVERFLOW:
+ return "EXCEPTION_INT_OVERFLOW";
+ case EXCEPTION_INVALID_DISPOSITION:
+ return "EXCEPTION_INVALID_DISPOSITION";
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
+ case EXCEPTION_PRIV_INSTRUCTION:
+ return "EXCEPTION_PRIV_INSTRUCTION";
+ case EXCEPTION_SINGLE_STEP:
+ return "EXCEPTION_SINGLE_STEP";
+ case EXCEPTION_STACK_OVERFLOW:
+ return "EXCEPTION_STACK_OVERFLOW";
+ default:
+ return "UNKNOWN EXCEPTION";
+ }
+}
+
+static void bli_windows_get_module_name(LPVOID address, PCHAR buffer, size_t size)
+{
+ HMODULE mod;
+ buffer[0] = 0;
+ if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) {
+ if (GetModuleFileName(mod, buffer, size)) {
+ PathStripPath(buffer);
+ }
+ }
+}
+
+static void bli_windows_get_module_version(const char *file, char *buffer, size_t buffersize)
+{
+ buffer[0] = 0;
+ DWORD verHandle = 0;
+ UINT size = 0;
+ LPBYTE lpBuffer = NULL;
+ DWORD verSize = GetFileVersionInfoSize(file, &verHandle);
+ if (verSize != 0) {
+ LPSTR verData = (LPSTR)MEM_callocN(verSize, "crash module version");
+
+ if (GetFileVersionInfo(file, verHandle, verSize, verData)) {
+ if (VerQueryValue(verData, "\\", (VOID FAR * FAR *)&lpBuffer, &size)) {
+ if (size) {
+ VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer;
+ /* Magic value from
+ * https://docs.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
+ */
+ if (verInfo->dwSignature == 0xfeef04bd) {
+ BLI_snprintf(buffer,
+ buffersize,
+ "%d.%d.%d.%d",
+ (verInfo->dwFileVersionMS >> 16) & 0xffff,
+ (verInfo->dwFileVersionMS >> 0) & 0xffff,
+ (verInfo->dwFileVersionLS >> 16) & 0xffff,
+ (verInfo->dwFileVersionLS >> 0) & 0xffff);
+ }
+ }
+ }
+ }
+ MEM_freeN(verData);
+ }
+}
+
+static void bli_windows_system_backtrace_exception_record(FILE *fp, PEXCEPTION_RECORD record)
+{
+ char module[MAX_PATH];
+ fprintf(fp, "Exception Record:\n\n");
+ fprintf(fp,
+ "ExceptionCode : %s\n",
+ bli_windows_get_exception_description(record->ExceptionCode));
+ fprintf(fp, "Exception Address : 0x%p\n", record->ExceptionAddress);
+ bli_windows_get_module_name(record->ExceptionAddress, module, sizeof(module));
+ fprintf(fp, "Exception Module : %s\n", module);
+ fprintf(fp, "Exception Flags : 0x%.8x\n", record->ExceptionFlags);
+ fprintf(fp, "Exception Parameters : 0x%x\n", record->NumberParameters);
+ for (DWORD idx = 0; idx < record->NumberParameters; idx++) {
+ fprintf(fp, "\tParameters[%d] : 0x%p\n", idx, (LPVOID *)record->ExceptionInformation[idx]);
+ }
+ if (record->ExceptionRecord) {
+ fprintf(fp, "Nested ");
+ bli_windows_system_backtrace_exception_record(fp, record->ExceptionRecord);
+ }
+ fprintf(fp, "\n\n");
+}
+
+static bool BLI_windows_system_backtrace_run_trace(FILE *fp, HANDLE hThread, PCONTEXT context)
+{
+ const int max_symbol_length = 100;
+
+ bool result = true;
+
+ PSYMBOL_INFO symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + max_symbol_length * sizeof(char),
+ "crash Symbol table");
+ symbolinfo->MaxNameLen = max_symbol_length - 1;
+ symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO);
+
+ STACKFRAME frame = {0};
+ frame.AddrPC.Offset = context->Rip;
+ frame.AddrPC.Mode = AddrModeFlat;
+ frame.AddrFrame.Offset = context->Rsp;
+ frame.AddrFrame.Mode = AddrModeFlat;
+ frame.AddrStack.Offset = context->Rsp;
+ frame.AddrStack.Mode = AddrModeFlat;
+
+ while (true) {
+ if (StackWalk64(IMAGE_FILE_MACHINE_AMD64,
+ GetCurrentProcess(),
+ hThread,
+ &frame,
+ context,
+ NULL,
+ SymFunctionTableAccess64,
+ SymGetModuleBase64,
+ 0)) {
+ if (frame.AddrPC.Offset) {
+ char module[MAX_PATH];
+
+ bli_windows_get_module_name((LPVOID)frame.AddrPC.Offset, module, sizeof(module));
+
+ if (SymFromAddr(GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), 0, symbolinfo)) {
+ fprintf(fp, "%-20s:0x%p %s", module, (LPVOID)symbolinfo->Address, symbolinfo->Name);
+ IMAGEHLP_LINE lineinfo;
+ lineinfo.SizeOfStruct = sizeof(lineinfo);
+ DWORD displacement = 0;
+ if (SymGetLineFromAddr(
+ GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), &displacement, &lineinfo)) {
+ fprintf(fp, " %s:%d", lineinfo.FileName, lineinfo.LineNumber);
+ }
+ fprintf(fp, "\n");
+ }
+ else {
+ fprintf(fp,
+ "%-20s:0x%p %s\n",
+ module,
+ (LPVOID)frame.AddrPC.Offset,
+ "Symbols not available");
+ result = false;
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ MEM_freeN(symbolinfo);
+ fprintf(fp, "\n\n");
+ return result;
+}
+
+static void bli_windows_system_backtrace_stack_thread(FILE *fp, HANDLE hThread)
+{
+ if (hThread != GetCurrentThread()) {
+ SuspendThread(hThread);
+ }
+ CONTEXT context;
+ context.ContextFlags = CONTEXT_ALL;
+ if (!GetThreadContext(hThread, &context)) {
+ fprintf(fp, "Cannot get thread context : 0x0%.8x\n", GetLastError());
+ }
+ BLI_windows_system_backtrace_run_trace(fp, hThread, &context);
+ if (hThread != GetCurrentThread()) {
+ ResumeThread(hThread);
+ }
+}
+
+static void bli_windows_system_backtrace_modules(FILE *fp)
+{
+ fprintf(fp, "Loaded Modules :\n");
+ HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
+ if (hModuleSnap == INVALID_HANDLE_VALUE)
+ return;
+
+ MODULEENTRY32 me32;
+ me32.dwSize = sizeof(MODULEENTRY32);
+
+ if (!Module32First(hModuleSnap, &me32)) {
+ CloseHandle(hModuleSnap); // Must clean up the snapshot object!
+ fprintf(fp, " Error getting module list.\n");
+ return;
+ }
+
+ do {
+ if (me32.th32ProcessID == GetCurrentProcessId()) {
+ char version[MAX_PATH];
+ bli_windows_get_module_version(me32.szExePath, version, sizeof(version));
+ fprintf(fp, "0x%p %-20s %s\n", me32.modBaseAddr, version, me32.szModule);
+ }
+ } while (Module32Next(hModuleSnap, &me32));
+}
+
+static void bli_windows_system_backtrace_threads(FILE *fp)
+{
+ fprintf(fp, "Threads:\n");
+ HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
+ THREADENTRY32 te32;
+
+ hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+ if (hThreadSnap == INVALID_HANDLE_VALUE) {
+ fprintf(fp, "Unable to retrieve threads list.\n");
+ return;
+ }
+
+ te32.dwSize = sizeof(THREADENTRY32);
+
+ if (!Thread32First(hThreadSnap, &te32)) {
+ CloseHandle(hThreadSnap);
+ return;
+ }
+ do {
+ if (te32.th32OwnerProcessID == GetCurrentProcessId()) {
+ if (GetCurrentThreadId() != te32.th32ThreadID) {
+ fprintf(fp, "Thread : %.8x\n", te32.th32ThreadID);
+ HANDLE ht = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID);
+ bli_windows_system_backtrace_stack_thread(fp, ht);
+ CloseHandle(ht);
+ }
+ }
+ } while (Thread32Next(hThreadSnap, &te32));
+ CloseHandle(hThreadSnap);
+}
+
+static bool BLI_windows_system_backtrace_stack(FILE *fp)
+{
+ fprintf(fp, "Stack trace:\n");
+ CONTEXT TempContext = *current_exception->ContextRecord;
+ return BLI_windows_system_backtrace_run_trace(fp, GetCurrentThread(), &TempContext);
+}
+
+static bool bli_private_symbols_loaded()
+{
+ IMAGEHLP_MODULE64 m64;
+ m64.SizeOfStruct = sizeof(m64);
+ if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)GetModuleHandle(NULL), &m64)) {
+ PathStripPath(m64.LoadedPdbName);
+ return BLI_strcasecmp(m64.LoadedPdbName, "blender_private.pdb") == 0;
+ }
+ return false;
+}
+
+static void bli_load_symbols()
+{
+ /* If this is a developer station and the private pdb is already loaded leave it be. */
+ if (bli_private_symbols_loaded()) {
+ return;
+ }
+
+ char pdb_file[MAX_PATH] = {0};
+
+ /* get the currently executing image */
+ if (GetModuleFileNameA(NULL, pdb_file, sizeof(pdb_file))) {
+ /* remove the filename */
+ PathRemoveFileSpecA(pdb_file);
+ /* append blender.pdb */
+ PathAppendA(pdb_file, "blender.pdb");
+ if (PathFileExistsA(pdb_file)) {
+ HMODULE mod = GetModuleHandle(NULL);
+ if (mod) {
+ WIN32_FILE_ATTRIBUTE_DATA file_data;
+ if (GetFileAttributesExA(pdb_file, GetFileExInfoStandard, &file_data)) {
+ /* SymInitialize will try to load symbols on its own, so we first must unload whatever it
+ * did trying to help */
+ SymUnloadModule64(GetCurrentProcess(), (DWORD64)mod);
+
+ DWORD64 module_base = SymLoadModule(GetCurrentProcess(),
+ NULL,
+ pdb_file,
+ NULL,
+ (DWORD64)mod,
+ (DWORD)file_data.nFileSizeLow);
+ if (module_base == 0) {
+ fprintf(stderr,
+ "Error loading symbols %s\n\terror:0x%.8x\n\tsize = %d\n\tbase=0x%p\n",
+ pdb_file,
+ GetLastError(),
+ file_data.nFileSizeLow,
+ (LPVOID)mod);
+ }
+ }
+ }
+ }
+ }
+}
+
+void BLI_system_backtrace(FILE *fp)
+{
+ SymInitialize(GetCurrentProcess(), NULL, TRUE);
+ bli_load_symbols();
+ bli_windows_system_backtrace_exception_record(fp, current_exception->ExceptionRecord);
+ if (BLI_windows_system_backtrace_stack(fp)) {
+ /* When the blender symbols are missing the stack traces will be unreliable
+ * so only run if the previous step completed successfully. */
+ bli_windows_system_backtrace_threads(fp);
+ }
+ bli_windows_system_backtrace_modules(fp);
+ fputc(0, fp); /* Give our selves a nice zero terminator for later on */
+}
+
+void BLI_windows_handle_exception(EXCEPTION_POINTERS *exception)
+{
+ current_exception = exception;
+ fprintf(stderr,
+ "Error : %s\n",
+ bli_windows_get_exception_description(exception->ExceptionRecord->ExceptionCode));
+ fflush(stderr);
+
+ LPVOID address = exception->ExceptionRecord->ExceptionAddress;
+ fprintf(stderr, "Address : 0x%p\n", address);
+
+ CHAR modulename[MAX_PATH];
+ bli_windows_get_module_name(address, modulename, sizeof(modulename));
+ fprintf(stderr, "Module : %s\n", modulename);
+ fflush(stderr);
+}
diff --git a/source/blender/blenlib/intern/task_iterator.c b/source/blender/blenlib/intern/task_iterator.c
index 4ac012fa578..ee459ac2548 100644
--- a/source/blender/blenlib/intern/task_iterator.c
+++ b/source/blender/blenlib/intern/task_iterator.c
@@ -17,7 +17,7 @@
/** \file
* \ingroup bli
*
- * A generic task system which can be used for any task based subsystem.
+ * Parallel tasks over all elements in a container.
*/
#include <stdlib.h>
@@ -34,77 +34,12 @@
#include "atomic_ops.h"
-/* Parallel range routines */
-
-/**
- *
- * Main functions:
- * - #BLI_task_parallel_range
- * - #BLI_task_parallel_listbase (#ListBase - double linked list)
- *
- * TODO:
- * - #BLI_task_parallel_foreach_link (#Link - single linked list)
- * - #BLI_task_parallel_foreach_ghash/gset (#GHash/#GSet - hash & set)
- * - #BLI_task_parallel_foreach_mempool (#BLI_mempool - iterate over mempools)
- */
-
/* Allows to avoid using malloc for userdata_chunk in tasks, when small enough. */
#define MALLOCA(_size) ((_size) <= 8192) ? alloca((_size)) : MEM_mallocN((_size), __func__)
#define MALLOCA_FREE(_mem, _size) \
if (((_mem) != NULL) && ((_size) > 8192)) \
MEM_freeN((_mem))
-/* Stores all needed data to perform a parallelized iteration,
- * with a same operation (callback function).
- * It can be chained with other tasks in a single-linked list way. */
-typedef struct TaskParallelRangeState {
- struct TaskParallelRangeState *next;
-
- /* Start and end point of integer value iteration. */
- int start, stop;
-
- /* User-defined data, shared between all worker threads. */
- void *userdata_shared;
- /* User-defined callback function called for each value in [start, stop[ specified range. */
- TaskParallelRangeFunc func;
-
- /* Each instance of looping chunks will get a copy of this data
- * (similar to OpenMP's firstprivate).
- */
- void *initial_tls_memory; /* Pointer to actual user-defined 'tls' data. */
- size_t tls_data_size; /* Size of that data. */
-
- void *flatten_tls_storage; /* 'tls' copies of initial_tls_memory for each running task. */
- /* Number of 'tls' copies in the array, i.e. number of worker threads. */
- size_t num_elements_in_tls_storage;
-
- /* Function called from calling thread once whole range have been processed. */
- TaskParallelFinalizeFunc func_finalize;
-
- /* Current value of the iterator, shared between all threads (atomically updated). */
- int iter_value;
- int iter_chunk_num; /* Amount of iterations to process in a single step. */
-} TaskParallelRangeState;
-
-/* Stores all the parallel tasks for a single pool. */
-typedef struct TaskParallelRangePool {
- /* The workers' task pool. */
- TaskPool *pool;
- /* The number of worker tasks we need to create. */
- int num_tasks;
- /* The total number of iterations in all the added ranges. */
- int num_total_iters;
- /* The size (number of items) processed at once by a worker task. */
- int chunk_size;
-
- /* Linked list of range tasks to process. */
- TaskParallelRangeState *parallel_range_states;
- /* Current range task beeing processed, swapped atomically. */
- TaskParallelRangeState *current_state;
- /* Scheduling settings common to all tasks. */
- TaskParallelSettings *settings;
-} TaskParallelRangePool;
-
BLI_INLINE void task_parallel_calc_chunk_size(const TaskParallelSettings *settings,
const int tot_items,
int num_tasks,
@@ -149,429 +84,7 @@ BLI_INLINE void task_parallel_calc_chunk_size(const TaskParallelSettings *settin
}
BLI_assert(chunk_size > 0);
-
- if (tot_items > 0) {
- switch (settings->scheduling_mode) {
- case TASK_SCHEDULING_STATIC:
- *r_chunk_size = max_ii(chunk_size, tot_items / num_tasks);
- break;
- case TASK_SCHEDULING_DYNAMIC:
- *r_chunk_size = chunk_size;
- break;
- }
- }
- else {
- /* If total amount of items is unknown, we can only use dynamic scheduling. */
- *r_chunk_size = chunk_size;
- }
-}
-
-BLI_INLINE void task_parallel_range_calc_chunk_size(TaskParallelRangePool *range_pool)
-{
- int num_iters = 0;
- int min_num_iters = INT_MAX;
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state->next) {
- const int ni = state->stop - state->start;
- num_iters += ni;
- if (min_num_iters > ni) {
- min_num_iters = ni;
- }
- }
- range_pool->num_total_iters = num_iters;
- /* Note: Passing min_num_iters here instead of num_iters kind of partially breaks the 'static'
- * scheduling, but pooled range iterator is inherently non-static anyway, so adding a small level
- * of dynamic scheduling here should be fine. */
- task_parallel_calc_chunk_size(
- range_pool->settings, min_num_iters, range_pool->num_tasks, &range_pool->chunk_size);
-}
-
-BLI_INLINE bool parallel_range_next_iter_get(TaskParallelRangePool *__restrict range_pool,
- int *__restrict r_iter,
- int *__restrict r_count,
- TaskParallelRangeState **__restrict r_state)
-{
- /* We need an atomic op here as well to fetch the initial state, since some other thread might
- * have already updated it. */
- TaskParallelRangeState *current_state = atomic_cas_ptr(
- (void **)&range_pool->current_state, NULL, NULL);
-
- int previter = INT32_MAX;
-
- while (current_state != NULL && previter >= current_state->stop) {
- previter = atomic_fetch_and_add_int32(&current_state->iter_value, range_pool->chunk_size);
- *r_iter = previter;
- *r_count = max_ii(0, min_ii(range_pool->chunk_size, current_state->stop - previter));
-
- if (previter >= current_state->stop) {
- /* At this point the state we got is done, we need to go to the next one. In case some other
- * thread already did it, then this does nothing, and we'll just get current valid state
- * at start of the next loop. */
- TaskParallelRangeState *current_state_from_atomic_cas = atomic_cas_ptr(
- (void **)&range_pool->current_state, current_state, current_state->next);
-
- if (current_state == current_state_from_atomic_cas) {
- /* The atomic CAS operation was successful, we did update range_pool->current_state, so we
- * can safely switch to next state. */
- current_state = current_state->next;
- }
- else {
- /* The atomic CAS operation failed, but we still got range_pool->current_state value out of
- * it, just use it as our new current state. */
- current_state = current_state_from_atomic_cas;
- }
- }
- }
-
- *r_state = current_state;
- return (current_state != NULL && previter < current_state->stop);
-}
-
-static void parallel_range_func(TaskPool *__restrict pool, void *tls_data_idx, int thread_id)
-{
- TaskParallelRangePool *__restrict range_pool = BLI_task_pool_userdata(pool);
- TaskParallelTLS tls = {
- .thread_id = thread_id,
- .userdata_chunk = NULL,
- };
- TaskParallelRangeState *state;
- int iter, count;
- while (parallel_range_next_iter_get(range_pool, &iter, &count, &state)) {
- tls.userdata_chunk = (char *)state->flatten_tls_storage +
- (((size_t)POINTER_AS_INT(tls_data_idx)) * state->tls_data_size);
- for (int i = 0; i < count; i++) {
- state->func(state->userdata_shared, iter + i, &tls);
- }
- }
-}
-
-static void parallel_range_single_thread(TaskParallelRangePool *range_pool)
-{
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state->next) {
- const int start = state->start;
- const int stop = state->stop;
- void *userdata = state->userdata_shared;
- TaskParallelRangeFunc func = state->func;
-
- void *initial_tls_memory = state->initial_tls_memory;
- const size_t tls_data_size = state->tls_data_size;
- void *flatten_tls_storage = NULL;
- const bool use_tls_data = (tls_data_size != 0) && (initial_tls_memory != NULL);
- if (use_tls_data) {
- flatten_tls_storage = MALLOCA(tls_data_size);
- memcpy(flatten_tls_storage, initial_tls_memory, tls_data_size);
- }
- TaskParallelTLS tls = {
- .thread_id = 0,
- .userdata_chunk = flatten_tls_storage,
- };
- for (int i = start; i < stop; i++) {
- func(userdata, i, &tls);
- }
- if (state->func_finalize != NULL) {
- state->func_finalize(userdata, flatten_tls_storage);
- }
- MALLOCA_FREE(flatten_tls_storage, tls_data_size);
- }
-}
-
-/**
- * This function allows to parallelized for loops in a similar way to OpenMP's
- * 'parallel for' statement.
- *
- * See public API doc of ParallelRangeSettings for description of all settings.
- */
-void BLI_task_parallel_range(const int start,
- const int stop,
- void *userdata,
- TaskParallelRangeFunc func,
- TaskParallelSettings *settings)
-{
- if (start == stop) {
- return;
- }
-
- BLI_assert(start < stop);
-
- TaskParallelRangeState state = {
- .next = NULL,
- .start = start,
- .stop = stop,
- .userdata_shared = userdata,
- .func = func,
- .iter_value = start,
- .initial_tls_memory = settings->userdata_chunk,
- .tls_data_size = settings->userdata_chunk_size,
- .func_finalize = settings->func_finalize,
- };
- TaskParallelRangePool range_pool = {
- .pool = NULL, .parallel_range_states = &state, .current_state = NULL, .settings = settings};
- int i, num_threads, num_tasks;
-
- void *tls_data = settings->userdata_chunk;
- const size_t tls_data_size = settings->userdata_chunk_size;
- if (tls_data_size != 0) {
- BLI_assert(tls_data != NULL);
- }
- const bool use_tls_data = (tls_data_size != 0) && (tls_data != NULL);
- void *flatten_tls_storage = NULL;
-
- /* If it's not enough data to be crunched, don't bother with tasks at all,
- * do everything from the current thread.
- */
- if (!settings->use_threading) {
- parallel_range_single_thread(&range_pool);
- return;
- }
-
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- num_threads = BLI_task_scheduler_num_threads(task_scheduler);
-
- /* The idea here is to prevent creating task for each of the loop iterations
- * and instead have tasks which are evenly distributed across CPU cores and
- * pull next iter to be crunched using the queue.
- */
- range_pool.num_tasks = num_tasks = num_threads + 2;
-
- task_parallel_range_calc_chunk_size(&range_pool);
- range_pool.num_tasks = num_tasks = min_ii(num_tasks,
- max_ii(1, (stop - start) / range_pool.chunk_size));
-
- if (num_tasks == 1) {
- parallel_range_single_thread(&range_pool);
- return;
- }
-
- TaskPool *task_pool = range_pool.pool = BLI_task_pool_create_suspended(
- task_scheduler, &range_pool, TASK_PRIORITY_HIGH);
-
- range_pool.current_state = &state;
-
- if (use_tls_data) {
- state.flatten_tls_storage = flatten_tls_storage = MALLOCA(tls_data_size * (size_t)num_tasks);
- state.tls_data_size = tls_data_size;
- }
-
- const int thread_id = BLI_task_pool_creator_thread_id(task_pool);
- for (i = 0; i < num_tasks; i++) {
- if (use_tls_data) {
- void *userdata_chunk_local = (char *)flatten_tls_storage + (tls_data_size * (size_t)i);
- memcpy(userdata_chunk_local, tls_data, tls_data_size);
- }
- /* Use this pool's pre-allocated tasks. */
- BLI_task_pool_push_from_thread(
- task_pool, parallel_range_func, POINTER_FROM_INT(i), false, NULL, thread_id);
- }
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- if (use_tls_data) {
- if (settings->func_finalize != NULL) {
- for (i = 0; i < num_tasks; i++) {
- void *userdata_chunk_local = (char *)flatten_tls_storage + (tls_data_size * (size_t)i);
- settings->func_finalize(userdata, userdata_chunk_local);
- }
- }
- MALLOCA_FREE(flatten_tls_storage, tls_data_size * (size_t)num_tasks);
- }
-}
-
-/**
- * Initialize a task pool to parallelize several for loops at the same time.
- *
- * See public API doc of ParallelRangeSettings for description of all settings.
- * Note that loop-specific settings (like 'tls' data or finalize function) must be left NULL here.
- * Only settings controlling how iteration is parallelized must be defined, as those will affect
- * all loops added to that pool.
- */
-TaskParallelRangePool *BLI_task_parallel_range_pool_init(const TaskParallelSettings *settings)
-{
- TaskParallelRangePool *range_pool = MEM_callocN(sizeof(*range_pool), __func__);
-
- BLI_assert(settings->userdata_chunk == NULL);
- BLI_assert(settings->func_finalize == NULL);
- range_pool->settings = MEM_mallocN(sizeof(*range_pool->settings), __func__);
- *range_pool->settings = *settings;
-
- return range_pool;
-}
-
-/**
- * Add a loop task to the pool. It does not execute it at all.
- *
- * See public API doc of ParallelRangeSettings for description of all settings.
- * Note that only 'tls'-related data are used here.
- */
-void BLI_task_parallel_range_pool_push(TaskParallelRangePool *range_pool,
- const int start,
- const int stop,
- void *userdata,
- TaskParallelRangeFunc func,
- const TaskParallelSettings *settings)
-{
- BLI_assert(range_pool->pool == NULL);
-
- if (start == stop) {
- return;
- }
-
- BLI_assert(start < stop);
- if (settings->userdata_chunk_size != 0) {
- BLI_assert(settings->userdata_chunk != NULL);
- }
-
- TaskParallelRangeState *state = MEM_callocN(sizeof(*state), __func__);
- state->start = start;
- state->stop = stop;
- state->userdata_shared = userdata;
- state->func = func;
- state->iter_value = start;
- state->initial_tls_memory = settings->userdata_chunk;
- state->tls_data_size = settings->userdata_chunk_size;
- state->func_finalize = settings->func_finalize;
-
- state->next = range_pool->parallel_range_states;
- range_pool->parallel_range_states = state;
-}
-
-static void parallel_range_func_finalize(TaskPool *__restrict pool,
- void *v_state,
- int UNUSED(thread_id))
-{
- TaskParallelRangePool *__restrict range_pool = BLI_task_pool_userdata(pool);
- TaskParallelRangeState *state = v_state;
-
- for (int i = 0; i < range_pool->num_tasks; i++) {
- void *tls_data = (char *)state->flatten_tls_storage + (state->tls_data_size * (size_t)i);
- state->func_finalize(state->userdata_shared, tls_data);
- }
-}
-
-/**
- * Run all tasks pushed to the range_pool.
- *
- * Note that the range pool is re-usable (you may push new tasks into it and call this function
- * again).
- */
-void BLI_task_parallel_range_pool_work_and_wait(TaskParallelRangePool *range_pool)
-{
- BLI_assert(range_pool->pool == NULL);
-
- /* If it's not enough data to be crunched, don't bother with tasks at all,
- * do everything from the current thread.
- */
- if (!range_pool->settings->use_threading) {
- parallel_range_single_thread(range_pool);
- return;
- }
-
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- const int num_threads = BLI_task_scheduler_num_threads(task_scheduler);
-
- /* The idea here is to prevent creating task for each of the loop iterations
- * and instead have tasks which are evenly distributed across CPU cores and
- * pull next iter to be crunched using the queue.
- */
- int num_tasks = num_threads + 2;
- range_pool->num_tasks = num_tasks;
-
- task_parallel_range_calc_chunk_size(range_pool);
- range_pool->num_tasks = num_tasks = min_ii(
- num_tasks, max_ii(1, range_pool->num_total_iters / range_pool->chunk_size));
-
- if (num_tasks == 1) {
- parallel_range_single_thread(range_pool);
- return;
- }
-
- /* We create all 'tls' data here in a single loop. */
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state->next) {
- void *userdata_chunk = state->initial_tls_memory;
- const size_t userdata_chunk_size = state->tls_data_size;
- if (userdata_chunk_size == 0) {
- BLI_assert(userdata_chunk == NULL);
- continue;
- }
-
- void *userdata_chunk_array = NULL;
- state->flatten_tls_storage = userdata_chunk_array = MALLOCA(userdata_chunk_size *
- (size_t)num_tasks);
- for (int i = 0; i < num_tasks; i++) {
- void *userdata_chunk_local = (char *)userdata_chunk_array +
- (userdata_chunk_size * (size_t)i);
- memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
- }
- }
-
- TaskPool *task_pool = range_pool->pool = BLI_task_pool_create_suspended(
- task_scheduler, range_pool, TASK_PRIORITY_HIGH);
-
- range_pool->current_state = range_pool->parallel_range_states;
- const int thread_id = BLI_task_pool_creator_thread_id(task_pool);
- for (int i = 0; i < num_tasks; i++) {
- BLI_task_pool_push_from_thread(
- task_pool, parallel_range_func, POINTER_FROM_INT(i), false, NULL, thread_id);
- }
-
- BLI_task_pool_work_and_wait(task_pool);
-
- BLI_assert(atomic_cas_ptr((void **)&range_pool->current_state, NULL, NULL) == NULL);
-
- /* Finalize all tasks. */
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state->next) {
- const size_t userdata_chunk_size = state->tls_data_size;
- void *userdata_chunk_array = state->flatten_tls_storage;
- UNUSED_VARS_NDEBUG(userdata_chunk_array);
- if (userdata_chunk_size == 0) {
- BLI_assert(userdata_chunk_array == NULL);
- continue;
- }
-
- if (state->func_finalize != NULL) {
- BLI_task_pool_push_from_thread(
- task_pool, parallel_range_func_finalize, state, false, NULL, thread_id);
- }
- }
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- range_pool->pool = NULL;
-
- /* Cleanup all tasks. */
- TaskParallelRangeState *state_next;
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state_next) {
- state_next = state->next;
-
- const size_t userdata_chunk_size = state->tls_data_size;
- void *userdata_chunk_array = state->flatten_tls_storage;
- if (userdata_chunk_size != 0) {
- BLI_assert(userdata_chunk_array != NULL);
- MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * (size_t)num_tasks);
- }
-
- MEM_freeN(state);
- }
- range_pool->parallel_range_states = NULL;
-}
-
-/**
- * Clear/free given \a range_pool.
- */
-void BLI_task_parallel_range_pool_free(TaskParallelRangePool *range_pool)
-{
- TaskParallelRangeState *state_next = NULL;
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state_next) {
- state_next = state->next;
- MEM_freeN(state);
- }
- MEM_freeN(range_pool->settings);
- MEM_freeN(range_pool);
+ *r_chunk_size = chunk_size;
}
typedef struct TaskParallelIteratorState {
@@ -586,20 +99,10 @@ typedef struct TaskParallelIteratorState {
int tot_items;
} TaskParallelIteratorState;
-BLI_INLINE void task_parallel_iterator_calc_chunk_size(const TaskParallelSettings *settings,
- const int num_tasks,
- TaskParallelIteratorState *state)
-{
- task_parallel_calc_chunk_size(
- settings, state->tot_items, num_tasks, &state->iter_shared.chunk_size);
-}
-
static void parallel_iterator_func_do(TaskParallelIteratorState *__restrict state,
- void *userdata_chunk,
- int threadid)
+ void *userdata_chunk)
{
TaskParallelTLS tls = {
- .thread_id = threadid,
.userdata_chunk = userdata_chunk,
};
@@ -652,11 +155,11 @@ static void parallel_iterator_func_do(TaskParallelIteratorState *__restrict stat
MALLOCA_FREE(current_chunk_indices, indices_size);
}
-static void parallel_iterator_func(TaskPool *__restrict pool, void *userdata_chunk, int threadid)
+static void parallel_iterator_func(TaskPool *__restrict pool, void *userdata_chunk)
{
- TaskParallelIteratorState *__restrict state = BLI_task_pool_userdata(pool);
+ TaskParallelIteratorState *__restrict state = BLI_task_pool_user_data(pool);
- parallel_iterator_func_do(state, userdata_chunk, threadid);
+ parallel_iterator_func_do(state, userdata_chunk);
}
static void task_parallel_iterator_no_threads(const TaskParallelSettings *settings,
@@ -675,23 +178,21 @@ static void task_parallel_iterator_no_threads(const TaskParallelSettings *settin
/* Also marking it as non-threaded for the iterator callback. */
state->iter_shared.spin_lock = NULL;
- parallel_iterator_func_do(state, userdata_chunk, 0);
+ parallel_iterator_func_do(state, userdata_chunk);
- if (use_userdata_chunk) {
- if (settings->func_finalize != NULL) {
- settings->func_finalize(state->userdata, userdata_chunk_local);
- }
- MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size);
+ if (use_userdata_chunk && settings->func_free != NULL) {
+ /* `func_free` should only free data that was created during execution of `func`. */
+ settings->func_free(state->userdata, userdata_chunk_local);
}
}
static void task_parallel_iterator_do(const TaskParallelSettings *settings,
TaskParallelIteratorState *state)
{
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- const int num_threads = BLI_task_scheduler_num_threads(task_scheduler);
+ const int num_threads = BLI_task_scheduler_num_threads();
- task_parallel_iterator_calc_chunk_size(settings, num_threads, state);
+ task_parallel_calc_chunk_size(
+ settings, state->tot_items, num_threads, &state->iter_shared.chunk_size);
if (!settings->use_threading) {
task_parallel_iterator_no_threads(settings, state);
@@ -720,31 +221,32 @@ static void task_parallel_iterator_do(const TaskParallelSettings *settings,
void *userdata_chunk_array = NULL;
const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
- TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, state, TASK_PRIORITY_HIGH);
+ TaskPool *task_pool = BLI_task_pool_create(state, TASK_PRIORITY_HIGH);
if (use_userdata_chunk) {
userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
}
- const int thread_id = BLI_task_pool_creator_thread_id(task_pool);
for (size_t i = 0; i < num_tasks; i++) {
if (use_userdata_chunk) {
userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
}
/* Use this pool's pre-allocated tasks. */
- BLI_task_pool_push_from_thread(
- task_pool, parallel_iterator_func, userdata_chunk_local, false, NULL, thread_id);
+ BLI_task_pool_push(task_pool, parallel_iterator_func, userdata_chunk_local, false, NULL);
}
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
- if (use_userdata_chunk) {
- if (settings->func_finalize != NULL) {
- for (size_t i = 0; i < num_tasks; i++) {
- userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
- settings->func_finalize(state->userdata, userdata_chunk_local);
+ if (use_userdata_chunk && (settings->func_reduce != NULL || settings->func_free != NULL)) {
+ for (size_t i = 0; i < num_tasks; i++) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ if (settings->func_reduce != NULL) {
+ settings->func_reduce(state->userdata, userdata_chunk, userdata_chunk_local);
+ }
+ if (settings->func_free != NULL) {
+ settings->func_free(state->userdata, userdata_chunk_local);
}
}
MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks);
@@ -847,9 +349,9 @@ typedef struct ParallelMempoolState {
TaskParallelMempoolFunc func;
} ParallelMempoolState;
-static void parallel_mempool_func(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid))
+static void parallel_mempool_func(TaskPool *__restrict pool, void *taskdata)
{
- ParallelMempoolState *__restrict state = BLI_task_pool_userdata(pool);
+ ParallelMempoolState *__restrict state = BLI_task_pool_user_data(pool);
BLI_mempool_iter *iter = taskdata;
MempoolIterData *item;
@@ -875,7 +377,6 @@ void BLI_task_parallel_mempool(BLI_mempool *mempool,
TaskParallelMempoolFunc func,
const bool use_threading)
{
- TaskScheduler *task_scheduler;
TaskPool *task_pool;
ParallelMempoolState state;
int i, num_threads, num_tasks;
@@ -895,9 +396,8 @@ void BLI_task_parallel_mempool(BLI_mempool *mempool,
return;
}
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create_suspended(task_scheduler, &state, TASK_PRIORITY_HIGH);
- num_threads = BLI_task_scheduler_num_threads(task_scheduler);
+ task_pool = BLI_task_pool_create(&state, TASK_PRIORITY_HIGH);
+ num_threads = BLI_task_scheduler_num_threads();
/* The idea here is to prevent creating task for each of the loop iterations
* and instead have tasks which are evenly distributed across CPU cores and
@@ -911,11 +411,9 @@ void BLI_task_parallel_mempool(BLI_mempool *mempool,
BLI_mempool_iter *mempool_iterators = BLI_mempool_iter_threadsafe_create(mempool,
(size_t)num_tasks);
- const int thread_id = BLI_task_pool_creator_thread_id(task_pool);
for (i = 0; i < num_tasks; i++) {
/* Use this pool's pre-allocated tasks. */
- BLI_task_pool_push_from_thread(
- task_pool, parallel_mempool_func, &mempool_iterators[i], false, NULL, thread_id);
+ BLI_task_pool_push(task_pool, parallel_mempool_func, &mempool_iterators[i], false, NULL);
}
BLI_task_pool_work_and_wait(task_pool);
diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc
index 8085d495248..b0d7df92343 100644
--- a/source/blender/blenlib/intern/task_pool.cc
+++ b/source/blender/blenlib/intern/task_pool.cc
@@ -17,731 +17,374 @@
/** \file
* \ingroup bli
*
- * A generic task system which can be used for any task based subsystem.
+ * Task pool to run tasks in parallel.
*/
+#include <memory>
#include <stdlib.h>
+#include <utility>
#include "MEM_guardedalloc.h"
#include "DNA_listBase.h"
-#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_mempool.h"
#include "BLI_task.h"
#include "BLI_threads.h"
-#include "atomic_ops.h"
-
-/* Define this to enable some detailed statistic print. */
-#undef DEBUG_STATS
-
-/* Types */
-
-/* Number of per-thread pre-allocated tasks.
- *
- * For more details see description of TaskMemPool.
- */
-#define MEMPOOL_SIZE 256
-
-/* Number of tasks which are pushed directly to local thread queue.
- *
- * This allows thread to fetch next task without locking the whole queue.
- */
-#define LOCAL_QUEUE_SIZE 1
-
-/* Number of tasks which are allowed to be scheduled in a delayed manner.
- *
- * This allows to use less locks per graph node children schedule. More details
- * could be found at TaskThreadLocalStorage::do_delayed_push.
- */
-#define DELAYED_QUEUE_SIZE 4096
-
-#ifndef NDEBUG
-# define ASSERT_THREAD_ID(scheduler, thread_id) \
- do { \
- if (!BLI_thread_is_main()) { \
- TaskThread *thread = (TaskThread *)pthread_getspecific(scheduler->tls_id_key); \
- if (thread == NULL) { \
- BLI_assert(thread_id == 0); \
- } \
- else { \
- BLI_assert(thread_id == thread->id); \
- } \
- } \
- else { \
- BLI_assert(thread_id == 0); \
- } \
- } while (false)
-#else
-# define ASSERT_THREAD_ID(scheduler, thread_id)
+#ifdef WITH_TBB
+/* Quiet top level deprecation message, unrelated to API usage here. */
+# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
+# include <tbb/tbb.h>
#endif
-typedef struct Task {
- struct Task *next, *prev;
+/* Task
+ *
+ * Unit of work to execute. This is a C++ class to work with TBB. */
+class Task {
+ public:
+ TaskPool *pool;
TaskRunFunction run;
void *taskdata;
bool free_taskdata;
TaskFreeFunction freedata;
- TaskPool *pool;
-} Task;
-/* This is a per-thread storage of pre-allocated tasks.
- *
- * The idea behind this is simple: reduce amount of malloc() calls when pushing
- * new task to the pool. This is done by keeping memory from the tasks which
- * were finished already, so instead of freeing that memory we put it to the
- * pool for the later re-use.
- *
- * The tricky part here is to avoid any inter-thread synchronization, hence no
- * lock must exist around this pool. The pool will become an owner of the pointer
- * from freed task, and only corresponding thread will be able to use this pool
- * (no memory stealing and such).
- *
- * This leads to the following use of the pool:
- *
- * - task_push() should provide proper thread ID from which the task is being
- * pushed from.
- *
- * - Task allocation function which check corresponding memory pool and if there
- * is any memory in there it'll mark memory as re-used, remove it from the pool
- * and use that memory for the new task.
- *
- * At this moment task queue owns the memory.
- *
- * - When task is done and task_free() is called the memory will be put to the
- * pool which corresponds to a thread which handled the task.
- */
-typedef struct TaskMemPool {
- /* Number of pre-allocated tasks in the pool. */
- int num_tasks;
- /* Pre-allocated task memory pointers. */
- Task *tasks[MEMPOOL_SIZE];
-} TaskMemPool;
-
-#ifdef DEBUG_STATS
-typedef struct TaskMemPoolStats {
- /* Number of allocations. */
- int num_alloc;
- /* Number of avoided allocations (pointer was re-used from the pool). */
- int num_reuse;
- /* Number of discarded memory due to pool saturation, */
- int num_discard;
-} TaskMemPoolStats;
-#endif
-
-typedef struct TaskThreadLocalStorage {
- /* Memory pool for faster task allocation.
- * The idea is to re-use memory of finished/discarded tasks by this thread.
- */
- TaskMemPool task_mempool;
-
- /* Local queue keeps thread alive by keeping small amount of tasks ready
- * to be picked up without causing global thread locks for synchronization.
- */
- int num_local_queue;
- Task *local_queue[LOCAL_QUEUE_SIZE];
-
- /* Thread can be marked for delayed tasks push. This is helpful when it's
- * know that lots of subsequent task pushed will happen from the same thread
- * without "interrupting" for task execution.
- *
- * We try to accumulate as much tasks as possible in a local queue without
- * any locks first, and then we push all of them into a scheduler's queue
- * from within a single mutex lock.
- */
- bool do_delayed_push;
- int num_delayed_queue;
- Task *delayed_queue[DELAYED_QUEUE_SIZE];
-} TaskThreadLocalStorage;
-
-struct TaskPool {
- TaskScheduler *scheduler;
-
- volatile size_t num;
- ThreadMutex num_mutex;
- ThreadCondition num_cond;
-
- void *userdata;
- ThreadMutex user_mutex;
+ Task(TaskPool *pool,
+ TaskRunFunction run,
+ void *taskdata,
+ bool free_taskdata,
+ TaskFreeFunction freedata)
+ : pool(pool), run(run), taskdata(taskdata), free_taskdata(free_taskdata), freedata(freedata)
+ {
+ }
- volatile bool do_cancel;
- volatile bool do_work;
+ ~Task()
+ {
+ if (free_taskdata) {
+ if (freedata) {
+ freedata(pool, taskdata);
+ }
+ else {
+ MEM_freeN(taskdata);
+ }
+ }
+ }
- volatile bool is_suspended;
- bool start_suspended;
- ListBase suspended_queue;
- size_t num_suspended;
+ /* Move constructor. */
+ Task(Task &&other)
+ : pool(other.pool),
+ run(other.run),
+ taskdata(other.taskdata),
+ free_taskdata(other.free_taskdata),
+ freedata(other.freedata)
+ {
+ other.pool = NULL;
+ other.run = NULL;
+ other.taskdata = NULL;
+ other.free_taskdata = false;
+ other.freedata = NULL;
+ }
- TaskPriority priority;
+ /* Execute task. */
+ void operator()() const
+ {
+ run(pool, taskdata);
+ }
- /* If set, this pool may never be work_and_wait'ed, which means TaskScheduler
- * has to use its special background fallback thread in case we are in
- * single-threaded situation.
- */
- bool run_in_background;
+ /* For performance, ensure we never copy the task and only move it. */
+ Task(const Task &other) = delete;
+ Task &operator=(const Task &other) = delete;
+ Task &operator=(Task &&other) = delete;
+};
- /* This is a task scheduler's ID of a thread at which pool was constructed.
- * It will be used to access task TLS.
- */
- int thread_id;
+/* TBB Task Group.
+ *
+ * Subclass since there seems to be no other way to set priority. */
+
+#ifdef WITH_TBB
+class TBBTaskGroup : public tbb::task_group {
+ public:
+ TBBTaskGroup(TaskPriority priority)
+ {
+ switch (priority) {
+ case TASK_PRIORITY_LOW:
+ my_context.set_priority(tbb::priority_low);
+ break;
+ case TASK_PRIORITY_HIGH:
+ my_context.set_priority(tbb::priority_normal);
+ break;
+ }
+ }
- /* For the pools which are created from non-main thread which is not a
- * scheduler worker thread we can't re-use any of scheduler's threads TLS
- * and have to use our own one.
- */
- bool use_local_tls;
- TaskThreadLocalStorage local_tls;
-#ifndef NDEBUG
- pthread_t creator_thread_id;
+ ~TBBTaskGroup()
+ {
+ }
+};
#endif
-#ifdef DEBUG_STATS
- TaskMemPoolStats *mempool_stats;
-#endif
-};
+/* Task Pool */
-struct TaskScheduler {
- pthread_t *threads;
- struct TaskThread *task_threads;
- int num_threads;
- bool background_thread_only;
+typedef enum TaskPoolType {
+ TASK_POOL_TBB,
+ TASK_POOL_TBB_SUSPENDED,
+ TASK_POOL_NO_THREADS,
+ TASK_POOL_BACKGROUND,
+ TASK_POOL_BACKGROUND_SERIAL,
+} TaskPoolType;
- ListBase queue;
- ThreadMutex queue_mutex;
- ThreadCondition queue_cond;
+struct TaskPool {
+ TaskPoolType type;
+ bool use_threads;
- ThreadMutex startup_mutex;
- ThreadCondition startup_cond;
- volatile int num_thread_started;
+ ThreadMutex user_mutex;
+ void *userdata;
- volatile bool do_exit;
+ /* TBB task pool. */
+#ifdef WITH_TBB
+ TBBTaskGroup tbb_group;
+#endif
+ volatile bool is_suspended;
+ BLI_mempool *suspended_mempool;
- /* NOTE: In pthread's TLS we store the whole TaskThread structure. */
- pthread_key_t tls_id_key;
+ /* Background task pool. */
+ ListBase background_threads;
+ ThreadQueue *background_queue;
+ volatile bool background_is_canceling;
};
-typedef struct TaskThread {
- TaskScheduler *scheduler;
- int id;
- TaskThreadLocalStorage tls;
-} TaskThread;
-
-/* Helper */
-BLI_INLINE void task_data_free(Task *task, const int thread_id)
-{
- if (task->free_taskdata) {
- if (task->freedata) {
- task->freedata(task->pool, task->taskdata, thread_id);
- }
- else {
- MEM_freeN(task->taskdata);
- }
- }
-}
-
-BLI_INLINE void initialize_task_tls(TaskThreadLocalStorage *tls)
-{
- memset(tls, 0, sizeof(TaskThreadLocalStorage));
-}
+/* TBB Task Pool.
+ *
+ * Task pool using the TBB scheduler for tasks. When building without TBB
+ * support or running Blender with -t 1, this reverts to single threaded.
+ *
+ * Tasks may be suspended until in all are created, to make it possible to
+ * initialize data structures and create tasks in a single pass. */
-BLI_INLINE TaskThreadLocalStorage *get_task_tls(TaskPool *pool, const int thread_id)
+static void tbb_task_pool_create(TaskPool *pool, TaskPriority priority)
{
- TaskScheduler *scheduler = pool->scheduler;
- BLI_assert(thread_id >= 0);
- BLI_assert(thread_id <= scheduler->num_threads);
- if (pool->use_local_tls && thread_id == 0) {
- BLI_assert(pool->thread_id == 0);
- BLI_assert(!BLI_thread_is_main());
- BLI_assert(pthread_equal(pthread_self(), pool->creator_thread_id));
- return &pool->local_tls;
- }
- if (thread_id == 0) {
- BLI_assert(BLI_thread_is_main());
- return &scheduler->task_threads[pool->thread_id].tls;
+ if (pool->type == TASK_POOL_TBB_SUSPENDED) {
+ pool->is_suspended = true;
+ pool->suspended_mempool = BLI_mempool_create(sizeof(Task), 512, 512, BLI_MEMPOOL_ALLOW_ITER);
}
- return &scheduler->task_threads[thread_id].tls;
-}
-BLI_INLINE void free_task_tls(TaskThreadLocalStorage *tls)
-{
- TaskMemPool *task_mempool = &tls->task_mempool;
- for (int i = 0; i < task_mempool->num_tasks; i++) {
- MEM_freeN(task_mempool->tasks[i]);
+#ifdef WITH_TBB
+ if (pool->use_threads) {
+ new (&pool->tbb_group) TBBTaskGroup(priority);
}
-}
-
-static Task *task_alloc(TaskPool *pool, const int thread_id)
-{
- BLI_assert(thread_id <= pool->scheduler->num_threads);
- if (thread_id != -1) {
- BLI_assert(thread_id >= 0);
- BLI_assert(thread_id <= pool->scheduler->num_threads);
- TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
- TaskMemPool *task_mempool = &tls->task_mempool;
- /* Try to re-use task memory from a thread local storage. */
- if (task_mempool->num_tasks > 0) {
- --task_mempool->num_tasks;
- /* Success! We've just avoided task allocation. */
-#ifdef DEBUG_STATS
- pool->mempool_stats[thread_id].num_reuse++;
-#endif
- return task_mempool->tasks[task_mempool->num_tasks];
- }
- /* We are doomed to allocate new task data. */
-#ifdef DEBUG_STATS
- pool->mempool_stats[thread_id].num_alloc++;
+#else
+ UNUSED_VARS(priority);
#endif
- }
- return (Task *)MEM_mallocN(sizeof(Task), "New task");
}
-static void task_free(TaskPool *pool, Task *task, const int thread_id)
+static void tbb_task_pool_run(TaskPool *pool, Task &&task)
{
- task_data_free(task, thread_id);
- BLI_assert(thread_id >= 0);
- BLI_assert(thread_id <= pool->scheduler->num_threads);
- if (thread_id == 0) {
- BLI_assert(pool->use_local_tls || BLI_thread_is_main());
+ if (pool->is_suspended) {
+ /* Suspended task that will be executed in work_and_wait(). */
+ Task *task_mem = (Task *)BLI_mempool_alloc(pool->suspended_mempool);
+ new (task_mem) Task(std::move(task));
+#ifdef __GNUC__
+ /* Work around apparent compiler bug where task is not properly copied
+ * to task_mem. This appears unrelated to the use of placement new or
+ * move semantics, happens even writing to a plain C struct. Rather the
+ * call into TBB seems to have some indirect effect. */
+ std::atomic_thread_fence(std::memory_order_release);
+#endif
}
- TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
- TaskMemPool *task_mempool = &tls->task_mempool;
- if (task_mempool->num_tasks < MEMPOOL_SIZE - 1) {
- /* Successfully allowed the task to be re-used later. */
- task_mempool->tasks[task_mempool->num_tasks] = task;
- ++task_mempool->num_tasks;
+#ifdef WITH_TBB
+ else if (pool->use_threads) {
+ /* Execute in TBB task group. */
+ pool->tbb_group.run(std::move(task));
}
- else {
- /* Local storage saturated, no other way than just discard
- * the memory.
- *
- * TODO(sergey): We can perhaps store such pointer in a global
- * scheduler pool, maybe it'll be faster than discarding and
- * allocating again.
- */
- MEM_freeN(task);
-#ifdef DEBUG_STATS
- pool->mempool_stats[thread_id].num_discard++;
#endif
+ else {
+ /* Execute immediately. */
+ task();
}
}
-/* Task Scheduler */
-
-static void task_pool_num_decrease(TaskPool *pool, size_t done)
+static void tbb_task_pool_work_and_wait(TaskPool *pool)
{
- BLI_mutex_lock(&pool->num_mutex);
+ /* Start any suspended task now. */
+ if (pool->suspended_mempool) {
+ pool->is_suspended = false;
- BLI_assert(pool->num >= done);
-
- pool->num -= done;
+ BLI_mempool_iter iter;
+ BLI_mempool_iternew(pool->suspended_mempool, &iter);
+ while (Task *task = (Task *)BLI_mempool_iterstep(&iter)) {
+ tbb_task_pool_run(pool, std::move(*task));
+ }
- if (pool->num == 0) {
- BLI_condition_notify_all(&pool->num_cond);
+ BLI_mempool_clear(pool->suspended_mempool);
}
- BLI_mutex_unlock(&pool->num_mutex);
+#ifdef WITH_TBB
+ if (pool->use_threads) {
+ /* This is called wait(), but internally it can actually do work. This
+ * matters because we don't want recursive usage of task pools to run
+ * out of threads and get stuck. */
+ pool->tbb_group.wait();
+ }
+#endif
}
-static void task_pool_num_increase(TaskPool *pool, size_t new_num)
+static void tbb_task_pool_cancel(TaskPool *pool)
{
- BLI_mutex_lock(&pool->num_mutex);
-
- pool->num += new_num;
- BLI_condition_notify_all(&pool->num_cond);
-
- BLI_mutex_unlock(&pool->num_mutex);
+#ifdef WITH_TBB
+ if (pool->use_threads) {
+ pool->tbb_group.cancel();
+ pool->tbb_group.wait();
+ }
+#else
+ UNUSED_VARS(pool);
+#endif
}
-static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task)
+static bool tbb_task_pool_canceled(TaskPool *pool)
{
- bool found_task = false;
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- while (!scheduler->queue.first && !scheduler->do_exit) {
- BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex);
+#ifdef WITH_TBB
+ if (pool->use_threads) {
+ return pool->tbb_group.is_canceling();
}
+#else
+ UNUSED_VARS(pool);
+#endif
- do {
- Task *current_task;
-
- /* Assuming we can only have a void queue in 'exit' case here seems logical
- * (we should only be here after our worker thread has been woken up from a
- * condition_wait(), which only happens after a new task was added to the queue),
- * but it is wrong.
- * Waiting on condition may wake up the thread even if condition is not signaled
- * (spurious wake-ups), and some race condition may also empty the queue **after**
- * condition has been signaled, but **before** awoken thread reaches this point...
- * See http://stackoverflow.com/questions/8594591
- *
- * So we only abort here if do_exit is set.
- */
- if (scheduler->do_exit) {
- BLI_mutex_unlock(&scheduler->queue_mutex);
- return false;
- }
-
- for (current_task = (Task *)scheduler->queue.first; current_task != NULL;
- current_task = current_task->next) {
- TaskPool *pool = current_task->pool;
-
- if (scheduler->background_thread_only && !pool->run_in_background) {
- continue;
- }
-
- *task = current_task;
- found_task = true;
- BLI_remlink(&scheduler->queue, *task);
- break;
- }
- if (!found_task) {
- BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex);
- }
- } while (!found_task);
-
- BLI_mutex_unlock(&scheduler->queue_mutex);
-
- return true;
+ return false;
}
-BLI_INLINE void handle_local_queue(TaskThreadLocalStorage *tls, const int thread_id)
+static void tbb_task_pool_free(TaskPool *pool)
{
- BLI_assert(!tls->do_delayed_push);
- while (tls->num_local_queue > 0) {
- /* We pop task from queue before handling it so handler of the task can
- * push next job to the local queue.
- */
- tls->num_local_queue--;
- Task *local_task = tls->local_queue[tls->num_local_queue];
- /* TODO(sergey): Double-check work_and_wait() doesn't handle other's
- * pool tasks.
- */
- TaskPool *local_pool = local_task->pool;
- local_task->run(local_pool, local_task->taskdata, thread_id);
- task_free(local_pool, local_task, thread_id);
+#ifdef WITH_TBB
+ if (pool->use_threads) {
+ pool->tbb_group.~TBBTaskGroup();
}
- BLI_assert(!tls->do_delayed_push);
-}
+#endif
-static void *task_scheduler_thread_run(void *thread_p)
-{
- TaskThread *thread = (TaskThread *)thread_p;
- TaskThreadLocalStorage *tls = &thread->tls;
- TaskScheduler *scheduler = thread->scheduler;
- int thread_id = thread->id;
- Task *task;
-
- pthread_setspecific(scheduler->tls_id_key, thread);
-
- /* signal the main thread when all threads have started */
- BLI_mutex_lock(&scheduler->startup_mutex);
- scheduler->num_thread_started++;
- if (scheduler->num_thread_started == scheduler->num_threads) {
- BLI_condition_notify_one(&scheduler->startup_cond);
+ if (pool->suspended_mempool) {
+ BLI_mempool_destroy(pool->suspended_mempool);
}
- BLI_mutex_unlock(&scheduler->startup_mutex);
-
- /* keep popping off tasks */
- while (task_scheduler_thread_wait_pop(scheduler, &task)) {
- TaskPool *pool = task->pool;
-
- /* run task */
- BLI_assert(!tls->do_delayed_push);
- task->run(pool, task->taskdata, thread_id);
- BLI_assert(!tls->do_delayed_push);
-
- /* delete task */
- task_free(pool, task, thread_id);
+}
- /* Handle all tasks from local queue. */
- handle_local_queue(tls, thread_id);
+/* Background Task Pool.
+ *
+ * Fallback for running background tasks when building without TBB. */
- /* notify pool task was done */
- task_pool_num_decrease(pool, 1);
+static void *background_task_run(void *userdata)
+{
+ TaskPool *pool = (TaskPool *)userdata;
+ while (Task *task = (Task *)BLI_thread_queue_pop(pool->background_queue)) {
+ (*task)();
+ task->~Task();
+ MEM_freeN(task);
}
-
return NULL;
}
-TaskScheduler *BLI_task_scheduler_create(int num_threads)
+static void background_task_pool_create(TaskPool *pool)
{
- TaskScheduler *scheduler = (TaskScheduler *)MEM_callocN(sizeof(TaskScheduler), "TaskScheduler");
-
- /* multiple places can use this task scheduler, sharing the same
- * threads, so we keep track of the number of users. */
- scheduler->do_exit = false;
-
- BLI_listbase_clear(&scheduler->queue);
- BLI_mutex_init(&scheduler->queue_mutex);
- BLI_condition_init(&scheduler->queue_cond);
-
- BLI_mutex_init(&scheduler->startup_mutex);
- BLI_condition_init(&scheduler->startup_cond);
- scheduler->num_thread_started = 0;
-
- if (num_threads == 0) {
- /* automatic number of threads will be main thread + num cores */
- num_threads = BLI_system_thread_count();
- }
-
- /* main thread will also work, so we count it too */
- num_threads -= 1;
-
- /* Add background-only thread if needed. */
- if (num_threads == 0) {
- scheduler->background_thread_only = true;
- num_threads = 1;
- }
-
- scheduler->task_threads = (TaskThread *)MEM_mallocN(sizeof(TaskThread) * (num_threads + 1),
- "TaskScheduler task threads");
-
- /* Initialize TLS for main thread. */
- initialize_task_tls(&scheduler->task_threads[0].tls);
-
- pthread_key_create(&scheduler->tls_id_key, NULL);
-
- /* launch threads that will be waiting for work */
- if (num_threads > 0) {
- int i;
-
- scheduler->num_threads = num_threads;
- scheduler->threads = (pthread_t *)MEM_callocN(sizeof(pthread_t) * num_threads,
- "TaskScheduler threads");
-
- for (i = 0; i < num_threads; i++) {
- TaskThread *thread = &scheduler->task_threads[i + 1];
- thread->scheduler = scheduler;
- thread->id = i + 1;
- initialize_task_tls(&thread->tls);
-
- if (pthread_create(&scheduler->threads[i], NULL, task_scheduler_thread_run, thread) != 0) {
- fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads);
- }
- }
- }
-
- /* Wait for all worker threads to start before returning to caller to prevent the case where
- * threads are still starting and pthread_join is called, which causes a deadlock on pthreads4w.
- */
- BLI_mutex_lock(&scheduler->startup_mutex);
- /* NOTE: Use loop here to avoid false-positive everything-is-ready caused by spontaneous thread
- * wake up. */
- while (scheduler->num_thread_started != num_threads) {
- BLI_condition_wait(&scheduler->startup_cond, &scheduler->startup_mutex);
- }
- BLI_mutex_unlock(&scheduler->startup_mutex);
-
- return scheduler;
+ pool->background_queue = BLI_thread_queue_init();
+ BLI_threadpool_init(&pool->background_threads, background_task_run, 1);
+ BLI_threadpool_insert(&pool->background_threads, pool);
}
-void BLI_task_scheduler_free(TaskScheduler *scheduler)
+static void background_task_pool_run(TaskPool *pool, Task &&task)
{
- Task *task;
-
- /* stop all waiting threads */
- BLI_mutex_lock(&scheduler->queue_mutex);
- scheduler->do_exit = true;
- BLI_condition_notify_all(&scheduler->queue_cond);
- BLI_mutex_unlock(&scheduler->queue_mutex);
-
- pthread_key_delete(scheduler->tls_id_key);
-
- /* delete threads */
- if (scheduler->threads) {
- int i;
-
- for (i = 0; i < scheduler->num_threads; i++) {
- if (pthread_join(scheduler->threads[i], NULL) != 0) {
- fprintf(stderr, "TaskScheduler failed to join thread %d/%d\n", i, scheduler->num_threads);
- }
- }
-
- MEM_freeN(scheduler->threads);
- }
-
- /* Delete task thread data */
- if (scheduler->task_threads) {
- for (int i = 0; i < scheduler->num_threads + 1; i++) {
- TaskThreadLocalStorage *tls = &scheduler->task_threads[i].tls;
- free_task_tls(tls);
- }
-
- MEM_freeN(scheduler->task_threads);
- }
-
- /* delete leftover tasks */
- for (task = (Task *)scheduler->queue.first; task; task = task->next) {
- task_data_free(task, 0);
- }
- BLI_freelistN(&scheduler->queue);
-
- /* delete mutex/condition */
- BLI_mutex_end(&scheduler->queue_mutex);
- BLI_condition_end(&scheduler->queue_cond);
- BLI_mutex_end(&scheduler->startup_mutex);
- BLI_condition_end(&scheduler->startup_cond);
-
- MEM_freeN(scheduler);
+ Task *task_mem = (Task *)MEM_mallocN(sizeof(Task), __func__);
+ new (task_mem) Task(std::move(task));
+ BLI_thread_queue_push(pool->background_queue, task_mem);
}
-int BLI_task_scheduler_num_threads(TaskScheduler *scheduler)
+static void background_task_pool_work_and_wait(TaskPool *pool)
{
- return scheduler->num_threads + 1;
+ /* Signal background thread to stop waiting for new tasks if none are
+ * left, and wait for tasks and thread to finish. */
+ BLI_thread_queue_nowait(pool->background_queue);
+ BLI_thread_queue_wait_finish(pool->background_queue);
+ BLI_threadpool_remove(&pool->background_threads, pool);
}
-static void task_scheduler_push(TaskScheduler *scheduler, Task *task, TaskPriority priority)
+static void background_task_pool_cancel(TaskPool *pool)
{
- task_pool_num_increase(task->pool, 1);
+ pool->background_is_canceling = true;
- /* add task to queue */
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- if (priority == TASK_PRIORITY_HIGH) {
- BLI_addhead(&scheduler->queue, task);
- }
- else {
- BLI_addtail(&scheduler->queue, task);
+ /* Remove tasks not yet started by background thread. */
+ BLI_thread_queue_nowait(pool->background_queue);
+ while (Task *task = (Task *)BLI_thread_queue_pop(pool->background_queue)) {
+ task->~Task();
+ MEM_freeN(task);
}
- BLI_condition_notify_one(&scheduler->queue_cond);
- BLI_mutex_unlock(&scheduler->queue_mutex);
+ /* Let background thread finish or cancel task it is working on. */
+ BLI_threadpool_remove(&pool->background_threads, pool);
+ pool->background_is_canceling = false;
}
-static void task_scheduler_push_all(TaskScheduler *scheduler,
- TaskPool *pool,
- Task **tasks,
- int num_tasks)
+static bool background_task_pool_canceled(TaskPool *pool)
{
- if (num_tasks == 0) {
- return;
- }
-
- task_pool_num_increase(pool, num_tasks);
-
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- for (int i = 0; i < num_tasks; i++) {
- BLI_addhead(&scheduler->queue, tasks[i]);
- }
-
- BLI_condition_notify_all(&scheduler->queue_cond);
- BLI_mutex_unlock(&scheduler->queue_mutex);
+ return pool->background_is_canceling;
}
-static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
+static void background_task_pool_free(TaskPool *pool)
{
- Task *task, *nexttask;
- size_t done = 0;
-
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- /* free all tasks from this pool from the queue */
- for (task = (Task *)scheduler->queue.first; task; task = nexttask) {
- nexttask = task->next;
-
- if (task->pool == pool) {
- task_data_free(task, pool->thread_id);
- BLI_freelinkN(&scheduler->queue, task);
+ background_task_pool_work_and_wait(pool);
- done++;
- }
- }
-
- BLI_mutex_unlock(&scheduler->queue_mutex);
-
- /* notify done */
- task_pool_num_decrease(pool, done);
+ BLI_threadpool_end(&pool->background_threads);
+ BLI_thread_queue_free(pool->background_queue);
}
/* Task Pool */
-static TaskPool *task_pool_create_ex(TaskScheduler *scheduler,
- void *userdata,
- const bool is_background,
- const bool is_suspended,
- TaskPriority priority)
+static TaskPool *task_pool_create_ex(void *userdata, TaskPoolType type, TaskPriority priority)
{
- TaskPool *pool = (TaskPool *)MEM_mallocN(sizeof(TaskPool), "TaskPool");
+ /* Ensure malloc will go fine from threads,
+ *
+ * This is needed because we could be in main thread here
+ * and malloc could be non-thread safe at this point because
+ * no other jobs are running.
+ */
+ BLI_threaded_malloc_begin();
-#ifndef NDEBUG
- /* Assert we do not try to create a background pool from some parent task -
- * those only work OK from main thread. */
- if (is_background) {
- const pthread_t thread_id = pthread_self();
- int i = scheduler->num_threads;
+ const bool use_threads = BLI_task_scheduler_num_threads() > 1 && type != TASK_POOL_NO_THREADS;
- while (i--) {
- BLI_assert(!pthread_equal(scheduler->threads[i], thread_id));
- }
+ /* Background task pool uses regular TBB scheduling if available. Only when
+ * building without TBB or running with -t 1 do we need to ensure these tasks
+ * do not block the main thread. */
+ if (type == TASK_POOL_BACKGROUND && use_threads) {
+ type = TASK_POOL_TBB;
}
-#endif
- pool->scheduler = scheduler;
- pool->num = 0;
- pool->do_cancel = false;
- pool->do_work = false;
- pool->is_suspended = is_suspended;
- pool->start_suspended = is_suspended;
- pool->num_suspended = 0;
- pool->suspended_queue.first = pool->suspended_queue.last = NULL;
- pool->priority = priority;
- pool->run_in_background = is_background;
- pool->use_local_tls = false;
-
- BLI_mutex_init(&pool->num_mutex);
- BLI_condition_init(&pool->num_cond);
+ /* Allocate task pool. */
+ TaskPool *pool = (TaskPool *)MEM_callocN(sizeof(TaskPool), "TaskPool");
+
+ pool->type = type;
+ pool->use_threads = use_threads;
pool->userdata = userdata;
BLI_mutex_init(&pool->user_mutex);
- if (BLI_thread_is_main()) {
- pool->thread_id = 0;
- }
- else {
- TaskThread *thread = (TaskThread *)pthread_getspecific(scheduler->tls_id_key);
- if (thread == NULL) {
- /* NOTE: Task pool is created from non-main thread which is not
- * managed by the task scheduler. We identify ourselves as thread ID
- * 0 but we do not use scheduler's TLS storage and use our own
- * instead to avoid any possible threading conflicts.
- */
- pool->thread_id = 0;
- pool->use_local_tls = true;
-#ifndef NDEBUG
- pool->creator_thread_id = pthread_self();
-#endif
- initialize_task_tls(&pool->local_tls);
- }
- else {
- pool->thread_id = thread->id;
- }
+ switch (type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ tbb_task_pool_create(pool, priority);
+ break;
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ background_task_pool_create(pool);
+ break;
}
-#ifdef DEBUG_STATS
- pool->mempool_stats = (TaskMemPoolStats *)MEM_callocN(
- sizeof(*pool->mempool_stats) * (scheduler->num_threads + 1), "per-taskpool mempool stats");
-#endif
-
- /* Ensure malloc will go fine from threads,
- *
- * This is needed because we could be in main thread here
- * and malloc could be non-thread safe at this point because
- * no other jobs are running.
- */
- BLI_threaded_malloc_begin();
-
return pool;
}
/**
* Create a normal task pool. Tasks will be executed as soon as they are added.
*/
-TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata, TaskPriority priority)
+TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority)
{
- return task_pool_create_ex(scheduler, userdata, false, false, priority);
+ return task_pool_create_ex(userdata, TASK_POOL_TBB, priority);
}
/**
@@ -756,11 +399,9 @@ TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata, TaskPri
* they could end never being executed, since the 'fallback' background thread is already
* busy with parent task in single-threaded context).
*/
-TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler,
- void *userdata,
- TaskPriority priority)
+TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority)
{
- return task_pool_create_ex(scheduler, userdata, true, false, priority);
+ return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND, priority);
}
/**
@@ -768,231 +409,117 @@ TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler,
* for until BLI_task_pool_work_and_wait() is called. This helps reducing threading
* overhead when pushing huge amount of small initial tasks from the main thread.
*/
-TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler,
- void *userdata,
- TaskPriority priority)
+TaskPool *BLI_task_pool_create_suspended(void *userdata, TaskPriority priority)
{
- return task_pool_create_ex(scheduler, userdata, false, true, priority);
+ return task_pool_create_ex(userdata, TASK_POOL_TBB_SUSPENDED, priority);
}
-void BLI_task_pool_free(TaskPool *pool)
+/**
+ * Single threaded task pool that executes pushed task immediately, for
+ * debugging purposes.
+ */
+TaskPool *BLI_task_pool_create_no_threads(void *userdata)
{
- BLI_task_pool_cancel(pool);
-
- BLI_mutex_end(&pool->num_mutex);
- BLI_condition_end(&pool->num_cond);
+ return task_pool_create_ex(userdata, TASK_POOL_NO_THREADS, TASK_PRIORITY_HIGH);
+}
- BLI_mutex_end(&pool->user_mutex);
+/**
+ * Task pool that executeds one task after the other, possibly on different threads
+ * but never in parallel.
+ */
+TaskPool *BLI_task_pool_create_background_serial(void *userdata, TaskPriority priority)
+{
+ return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND_SERIAL, priority);
+}
-#ifdef DEBUG_STATS
- printf("Thread ID Allocated Reused Discarded\n");
- for (int i = 0; i < pool->scheduler->num_threads + 1; i++) {
- printf("%02d %05d %05d %05d\n",
- i,
- pool->mempool_stats[i].num_alloc,
- pool->mempool_stats[i].num_reuse,
- pool->mempool_stats[i].num_discard);
+void BLI_task_pool_free(TaskPool *pool)
+{
+ switch (pool->type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ tbb_task_pool_free(pool);
+ break;
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ background_task_pool_free(pool);
+ break;
}
- MEM_freeN(pool->mempool_stats);
-#endif
- if (pool->use_local_tls) {
- free_task_tls(&pool->local_tls);
- }
+ BLI_mutex_end(&pool->user_mutex);
MEM_freeN(pool);
BLI_threaded_malloc_end();
}
-BLI_INLINE bool task_can_use_local_queues(TaskPool *pool, int thread_id)
-{
- return (thread_id != -1 && (thread_id != pool->thread_id || pool->do_work));
-}
-
-static void task_pool_push(TaskPool *pool,
- TaskRunFunction run,
- void *taskdata,
- bool free_taskdata,
- TaskFreeFunction freedata,
- int thread_id)
-{
- /* Allocate task and fill it's properties. */
- Task *task = task_alloc(pool, thread_id);
- task->run = run;
- task->taskdata = taskdata;
- task->free_taskdata = free_taskdata;
- task->freedata = freedata;
- task->pool = pool;
- /* For suspended pools we put everything yo a global queue first
- * and exit as soon as possible.
- *
- * This tasks will be moved to actual execution when pool is
- * activated by work_and_wait().
- */
- if (pool->is_suspended) {
- BLI_addhead(&pool->suspended_queue, task);
- atomic_fetch_and_add_z(&pool->num_suspended, 1);
- return;
- }
- /* Populate to any local queue first, this is cheapest push ever. */
- if (task_can_use_local_queues(pool, thread_id)) {
- ASSERT_THREAD_ID(pool->scheduler, thread_id);
- TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
- /* Try to push to a local execution queue.
- * These tasks will be picked up next.
- */
- if (tls->num_local_queue < LOCAL_QUEUE_SIZE) {
- tls->local_queue[tls->num_local_queue] = task;
- tls->num_local_queue++;
- return;
- }
- /* If we are in the delayed tasks push mode, we push tasks to a
- * temporary local queue first without any locks, and then move them
- * to global execution queue with a single lock.
- */
- if (tls->do_delayed_push && tls->num_delayed_queue < DELAYED_QUEUE_SIZE) {
- tls->delayed_queue[tls->num_delayed_queue] = task;
- tls->num_delayed_queue++;
- return;
- }
- }
- /* Do push to a global execution pool, slowest possible method,
- * causes quite reasonable amount of threading overhead.
- */
- task_scheduler_push(pool->scheduler, task, pool->priority);
-}
-
void BLI_task_pool_push(TaskPool *pool,
TaskRunFunction run,
void *taskdata,
bool free_taskdata,
TaskFreeFunction freedata)
{
- task_pool_push(pool, run, taskdata, free_taskdata, freedata, -1);
-}
+ Task task(pool, run, taskdata, free_taskdata, freedata);
-void BLI_task_pool_push_from_thread(TaskPool *pool,
- TaskRunFunction run,
- void *taskdata,
- bool free_taskdata,
- TaskFreeFunction freedata,
- int thread_id)
-{
- task_pool_push(pool, run, taskdata, free_taskdata, freedata, thread_id);
+ switch (pool->type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ tbb_task_pool_run(pool, std::move(task));
+ break;
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ background_task_pool_run(pool, std::move(task));
+ break;
+ }
}
void BLI_task_pool_work_and_wait(TaskPool *pool)
{
- TaskThreadLocalStorage *tls = get_task_tls(pool, pool->thread_id);
- TaskScheduler *scheduler = pool->scheduler;
-
- if (atomic_fetch_and_and_uint8((uint8_t *)&pool->is_suspended, 0)) {
- if (pool->num_suspended) {
- task_pool_num_increase(pool, pool->num_suspended);
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- BLI_movelisttolist(&scheduler->queue, &pool->suspended_queue);
-
- BLI_condition_notify_all(&scheduler->queue_cond);
- BLI_mutex_unlock(&scheduler->queue_mutex);
-
- pool->num_suspended = 0;
- }
- }
-
- pool->do_work = true;
-
- ASSERT_THREAD_ID(pool->scheduler, pool->thread_id);
-
- handle_local_queue(tls, pool->thread_id);
-
- BLI_mutex_lock(&pool->num_mutex);
-
- while (pool->num != 0) {
- Task *task, *work_task = NULL;
- bool found_task = false;
-
- BLI_mutex_unlock(&pool->num_mutex);
-
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- /* find task from this pool. if we get a task from another pool,
- * we can get into deadlock */
-
- for (task = (Task *)scheduler->queue.first; task; task = task->next) {
- if (task->pool == pool) {
- work_task = task;
- found_task = true;
- BLI_remlink(&scheduler->queue, task);
- break;
- }
- }
-
- BLI_mutex_unlock(&scheduler->queue_mutex);
-
- /* if found task, do it, otherwise wait until other tasks are done */
- if (found_task) {
- /* run task */
- BLI_assert(!tls->do_delayed_push);
- work_task->run(pool, work_task->taskdata, pool->thread_id);
- BLI_assert(!tls->do_delayed_push);
-
- /* delete task */
- task_free(pool, task, pool->thread_id);
-
- /* Handle all tasks from local queue. */
- handle_local_queue(tls, pool->thread_id);
-
- /* notify pool task was done */
- task_pool_num_decrease(pool, 1);
- }
-
- BLI_mutex_lock(&pool->num_mutex);
- if (pool->num == 0) {
+ switch (pool->type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ tbb_task_pool_work_and_wait(pool);
+ break;
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ background_task_pool_work_and_wait(pool);
break;
- }
-
- if (!found_task) {
- BLI_condition_wait(&pool->num_cond, &pool->num_mutex);
- }
}
-
- BLI_mutex_unlock(&pool->num_mutex);
-
- BLI_assert(tls->num_local_queue == 0);
-}
-
-void BLI_task_pool_work_wait_and_reset(TaskPool *pool)
-{
- BLI_task_pool_work_and_wait(pool);
-
- pool->do_work = false;
- pool->is_suspended = pool->start_suspended;
}
void BLI_task_pool_cancel(TaskPool *pool)
{
- pool->do_cancel = true;
-
- task_scheduler_clear(pool->scheduler, pool);
-
- /* wait until all entries are cleared */
- BLI_mutex_lock(&pool->num_mutex);
- while (pool->num) {
- BLI_condition_wait(&pool->num_cond, &pool->num_mutex);
+ switch (pool->type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ tbb_task_pool_cancel(pool);
+ break;
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ background_task_pool_cancel(pool);
+ break;
}
- BLI_mutex_unlock(&pool->num_mutex);
-
- pool->do_cancel = false;
}
bool BLI_task_pool_canceled(TaskPool *pool)
{
- return pool->do_cancel;
+ switch (pool->type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ return tbb_task_pool_canceled(pool);
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ return background_task_pool_canceled(pool);
+ }
+ BLI_assert("BLI_task_pool_canceled: Control flow should not come here!");
+ return false;
}
-void *BLI_task_pool_userdata(TaskPool *pool)
+void *BLI_task_pool_user_data(TaskPool *pool)
{
return pool->userdata;
}
@@ -1001,29 +528,3 @@ ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool)
{
return &pool->user_mutex;
}
-
-int BLI_task_pool_creator_thread_id(TaskPool *pool)
-{
- return pool->thread_id;
-}
-
-void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id)
-{
- if (task_can_use_local_queues(pool, thread_id)) {
- ASSERT_THREAD_ID(pool->scheduler, thread_id);
- TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
- tls->do_delayed_push = true;
- }
-}
-
-void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id)
-{
- if (task_can_use_local_queues(pool, thread_id)) {
- ASSERT_THREAD_ID(pool->scheduler, thread_id);
- TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
- BLI_assert(tls->do_delayed_push);
- task_scheduler_push_all(pool->scheduler, pool, tls->delayed_queue, tls->num_delayed_queue);
- tls->do_delayed_push = false;
- tls->num_delayed_queue = 0;
- }
-}
diff --git a/source/blender/blenkernel/intern/pbvh_parallel.cc b/source/blender/blenlib/intern/task_range.cc
index 2534fdea3ee..a8447c305e0 100644
--- a/source/blender/blenkernel/intern/pbvh_parallel.cc
+++ b/source/blender/blenlib/intern/task_range.cc
@@ -14,60 +14,72 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+/** \file
+ * \ingroup bli
+ *
+ * Task parallel range functions.
+ */
+
+#include <stdlib.h>
+
#include "MEM_guardedalloc.h"
+#include "DNA_listBase.h"
+
#include "BLI_task.h"
#include "BLI_threads.h"
-#include "BKE_pbvh.h"
-
#include "atomic_ops.h"
#ifdef WITH_TBB
-
/* Quiet top level deprecation message, unrelated to API usage here. */
# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
-
# include <tbb/tbb.h>
+#endif
+
+#ifdef WITH_TBB
/* Functor for running TBB parallel_for and parallel_reduce. */
-struct PBVHTask {
- PBVHParallelRangeFunc func;
+struct RangeTask {
+ TaskParallelRangeFunc func;
void *userdata;
- const PBVHParallelSettings *settings;
+ const TaskParallelSettings *settings;
void *userdata_chunk;
/* Root constructor. */
- PBVHTask(PBVHParallelRangeFunc func, void *userdata, const PBVHParallelSettings *settings)
+ RangeTask(TaskParallelRangeFunc func, void *userdata, const TaskParallelSettings *settings)
: func(func), userdata(userdata), settings(settings)
{
init_chunk(settings->userdata_chunk);
}
/* Copy constructor. */
- PBVHTask(const PBVHTask &other)
+ RangeTask(const RangeTask &other)
: func(other.func), userdata(other.userdata), settings(other.settings)
{
- init_chunk(other.userdata_chunk);
+ init_chunk(settings->userdata_chunk);
}
/* Splitting constructor for parallel reduce. */
- PBVHTask(PBVHTask &other, tbb::split)
+ RangeTask(RangeTask &other, tbb::split)
: func(other.func), userdata(other.userdata), settings(other.settings)
{
init_chunk(settings->userdata_chunk);
}
- ~PBVHTask()
+ ~RangeTask()
{
+ if (settings->func_free != NULL) {
+ settings->func_free(userdata, userdata_chunk);
+ }
MEM_SAFE_FREE(userdata_chunk);
}
void init_chunk(void *from_chunk)
{
if (from_chunk) {
- userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "PBVHTask");
+ userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "RangeTask");
memcpy(userdata_chunk, from_chunk, settings->userdata_chunk_size);
}
else {
@@ -78,59 +90,41 @@ struct PBVHTask {
void operator()(const tbb::blocked_range<int> &r) const
{
TaskParallelTLS tls;
- tls.thread_id = get_thread_id();
tls.userdata_chunk = userdata_chunk;
for (int i = r.begin(); i != r.end(); ++i) {
func(userdata, i, &tls);
}
}
- void join(const PBVHTask &other)
+ void join(const RangeTask &other)
{
settings->func_reduce(userdata, userdata_chunk, other.userdata_chunk);
}
-
- int get_thread_id() const
- {
- /* Get a unique thread ID for texture nodes. In the future we should get rid
- * of the thread ID and change texture evaluation to not require per-thread
- * storage that can't be efficiently allocated on the stack. */
- static tbb::enumerable_thread_specific<int> pbvh_thread_id(-1);
- static int pbvh_thread_id_counter = 0;
-
- int &thread_id = pbvh_thread_id.local();
- if (thread_id == -1) {
- thread_id = atomic_fetch_and_add_int32(&pbvh_thread_id_counter, 1);
- if (thread_id >= BLENDER_MAX_THREADS) {
- BLI_assert(!"Maximum number of threads exceeded for sculpting");
- thread_id = thread_id % BLENDER_MAX_THREADS;
- }
- }
- return thread_id;
- }
};
#endif
-void BKE_pbvh_parallel_range(const int start,
+void BLI_task_parallel_range(const int start,
const int stop,
void *userdata,
- PBVHParallelRangeFunc func,
- const struct PBVHParallelSettings *settings)
+ TaskParallelRangeFunc func,
+ const TaskParallelSettings *settings)
{
#ifdef WITH_TBB
/* Multithreading. */
- if (settings->use_threading) {
- PBVHTask task(func, userdata, settings);
+ if (settings->use_threading && BLI_task_scheduler_num_threads() > 1) {
+ RangeTask task(func, userdata, settings);
+ const size_t grainsize = MAX2(settings->min_iter_per_thread, 1);
+ const tbb::blocked_range<int> range(start, stop, grainsize);
if (settings->func_reduce) {
- parallel_reduce(tbb::blocked_range<int>(start, stop), task);
+ parallel_reduce(range, task);
if (settings->userdata_chunk) {
memcpy(settings->userdata_chunk, task.userdata_chunk, settings->userdata_chunk_size);
}
}
else {
- parallel_for(tbb::blocked_range<int>(start, stop), task);
+ parallel_for(range, task);
}
return;
@@ -140,9 +134,34 @@ void BKE_pbvh_parallel_range(const int start,
/* Single threaded. Nothing to reduce as everything is accumulated into the
* main userdata chunk directly. */
TaskParallelTLS tls;
- tls.thread_id = 0;
tls.userdata_chunk = settings->userdata_chunk;
for (int i = start; i < stop; i++) {
func(userdata, i, &tls);
}
+ if (settings->func_free != NULL) {
+ settings->func_free(userdata, settings->userdata_chunk);
+ }
+}
+
+int BLI_task_parallel_thread_id(const TaskParallelTLS *UNUSED(tls))
+{
+#ifdef WITH_TBB
+ /* Get a unique thread ID for texture nodes. In the future we should get rid
+ * of the thread ID and change texture evaluation to not require per-thread
+ * storage that can't be efficiently allocated on the stack. */
+ static tbb::enumerable_thread_specific<int> tbb_thread_id(-1);
+ static int tbb_thread_id_counter = 0;
+
+ int &thread_id = tbb_thread_id.local();
+ if (thread_id == -1) {
+ thread_id = atomic_fetch_and_add_int32(&tbb_thread_id_counter, 1);
+ if (thread_id >= BLENDER_MAX_THREADS) {
+ BLI_assert(!"Maximum number of threads exceeded for sculpting");
+ thread_id = thread_id % BLENDER_MAX_THREADS;
+ }
+ }
+ return thread_id;
+#else
+ return 0;
+#endif
}
diff --git a/source/blender/blenlib/intern/task_scheduler.cc b/source/blender/blenlib/intern/task_scheduler.cc
new file mode 100644
index 00000000000..682fee5c46d
--- /dev/null
+++ b/source/blender/blenlib/intern/task_scheduler.cc
@@ -0,0 +1,73 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ *
+ * Task scheduler initialization.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_task.h"
+#include "BLI_threads.h"
+
+#ifdef WITH_TBB
+/* Quiet top level deprecation message, unrelated to API usage here. */
+# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
+# include <tbb/tbb.h>
+#endif
+
+/* Task Scheduler */
+
+static int task_scheduler_num_threads = 1;
+#ifdef WITH_TBB
+static tbb::global_control *task_scheduler_global_control = nullptr;
+#endif
+
+void BLI_task_scheduler_init()
+{
+#ifdef WITH_TBB
+ const int num_threads_override = BLI_system_num_threads_override_get();
+
+ if (num_threads_override > 0) {
+ /* Override number of threads. This settings is used within the lifetime
+ * of tbb::global_control, so we allocate it on the heap. */
+ task_scheduler_global_control = OBJECT_GUARDED_NEW(
+ tbb::global_control, tbb::global_control::max_allowed_parallelism, num_threads_override);
+ task_scheduler_num_threads = num_threads_override;
+ }
+ else {
+ /* Let TBB choose the number of threads. For (legacy) code that calss
+ * BLI_task_scheduler_num_threads() we provide the system thread count.
+ * Ideally such code should be rewritten not to use the number of threads
+ * at all. */
+ task_scheduler_num_threads = BLI_system_thread_count();
+ }
+#endif
+}
+
+void BLI_task_scheduler_exit()
+{
+#ifdef WITH_TBB
+ OBJECT_GUARDED_DELETE(task_scheduler_global_control, tbb::global_control);
+#endif
+}
+
+int BLI_task_scheduler_num_threads()
+{
+ return task_scheduler_num_threads;
+}
diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c
index 31e8581590a..f535798f86d 100644
--- a/source/blender/blenlib/intern/threads.c
+++ b/source/blender/blenlib/intern/threads.c
@@ -61,9 +61,6 @@ extern pthread_key_t gomp_tls_key;
static void *thread_tls_data;
#endif
-/* We're using one global task scheduler for all kind of tasks. */
-static TaskScheduler *task_scheduler = NULL;
-
/* ********** basic thread control API ************
*
* Many thread cases have an X amount of jobs, and only an Y amount of
@@ -157,27 +154,9 @@ void BLI_threadapi_init(void)
void BLI_threadapi_exit(void)
{
- if (task_scheduler) {
- BLI_task_scheduler_free(task_scheduler);
- task_scheduler = NULL;
- }
BLI_spin_end(&_malloc_lock);
}
-TaskScheduler *BLI_task_scheduler_get(void)
-{
- if (task_scheduler == NULL) {
- int tot_thread = BLI_system_thread_count();
-
- /* Do a lazy initialization, so it happens after
- * command line arguments parsing
- */
- task_scheduler = BLI_task_scheduler_create(tot_thread);
- }
-
- return task_scheduler;
-}
-
/* tot = 0 only initializes malloc mutex in a safe way (see sequence.c)
* problem otherwise: scene render will kill of the mutex!
*/
@@ -839,11 +818,6 @@ void BLI_threaded_malloc_begin(void)
unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1);
if (level == 0) {
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
- /* There is a little chance that two threads will need to access to a
- * scheduler which was not yet created from main thread. which could
- * cause scheduler created multiple times.
- */
- BLI_task_scheduler_get();
}
}
diff --git a/source/blender/blenlib/intern/timeit.cc b/source/blender/blenlib/intern/timeit.cc
new file mode 100644
index 00000000000..bab8fd81746
--- /dev/null
+++ b/source/blender/blenlib/intern/timeit.cc
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_timeit.hh"
+
+namespace BLI {
+namespace Timeit {
+
+void print_duration(Nanoseconds duration)
+{
+ if (duration < std::chrono::microseconds(100)) {
+ std::cout << duration.count() << " ns";
+ }
+ else if (duration < std::chrono::seconds(5)) {
+ std::cout << duration.count() / 1.0e6 << " ms";
+ }
+ else {
+ std::cout << duration.count() / 1.0e9 << " s";
+ }
+}
+
+} // namespace Timeit
+} // namespace BLI
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 450d3fc2371..1555b9231ed 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -53,6 +53,7 @@ set(SRC
intern/versioning_260.c
intern/versioning_270.c
intern/versioning_280.c
+ intern/versioning_290.c
intern/versioning_cycles.c
intern/versioning_defaults.c
intern/versioning_dna.c
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index cb567147224..418750a8df2 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -86,6 +86,7 @@
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
@@ -117,7 +118,7 @@
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_fluid.h"
#include "BKE_global.h" // for G
#include "BKE_gpencil_modifier.h"
@@ -146,6 +147,7 @@
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
+#include "BKE_simulation.h"
#include "BKE_sound.h"
#include "BKE_volume.h"
#include "BKE_workspace.h"
@@ -3600,6 +3602,45 @@ static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook
/** \name Read ID: Node Tree
* \{ */
+static void lib_link_node_socket(FileData *fd, Library *lib, bNodeSocket *sock)
+{
+ IDP_LibLinkProperty(sock->prop, fd);
+
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ default_value->value = newlibadr(fd, lib, default_value->value);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ default_value->value = newlibadr(fd, lib, default_value->value);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+}
+
+static void lib_link_node_sockets(FileData *fd, Library *lib, ListBase *sockets)
+{
+ LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
+ lib_link_node_socket(fd, lib, sock);
+ }
+}
+
/* Single node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(FileData *fd, Library *lib, bNodeTree *ntree)
{
@@ -3614,20 +3655,12 @@ static void lib_link_ntree(FileData *fd, Library *lib, bNodeTree *ntree)
node->id = newlibadr(fd, lib, node->id);
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- IDP_LibLinkProperty(sock->prop, fd);
- }
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
- IDP_LibLinkProperty(sock->prop, fd);
- }
+ lib_link_node_sockets(fd, lib, &node->inputs);
+ lib_link_node_sockets(fd, lib, &node->outputs);
}
- LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
- IDP_LibLinkProperty(sock->prop, fd);
- }
- LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
- IDP_LibLinkProperty(sock->prop, fd);
- }
+ lib_link_node_sockets(fd, lib, &ntree->inputs);
+ lib_link_node_sockets(fd, lib, &ntree->outputs);
/* Set node->typeinfo pointers. This is done in lib linking, after the
* first versioning that can change types still without functions that
@@ -9147,6 +9180,24 @@ static void direct_link_volume(FileData *fd, Volume *volume)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Read ID: Simulation
+ * \{ */
+
+static void lib_link_simulation(FileData *UNUSED(fd),
+ Main *UNUSED(main),
+ Simulation *UNUSED(simulation))
+{
+}
+
+static void direct_link_simulation(FileData *fd, Simulation *simulation)
+{
+ simulation->adt = newdataadr(fd, simulation->adt);
+ direct_link_animdata(fd, simulation->adt);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Read Library Data Block
* \{ */
@@ -9264,6 +9315,8 @@ static const char *dataname(short id_code)
return "Data from PT";
case ID_VO:
return "Data from VO";
+ case ID_SIM:
+ return "Data from SIM";
}
return "Data from Lib Block";
}
@@ -9415,6 +9468,9 @@ static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *
case ID_VO:
direct_link_volume(fd, (Volume *)id);
break;
+ case ID_SIM:
+ direct_link_simulation(fd, (Simulation *)id);
+ break;
}
return success;
@@ -9933,6 +9989,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
blo_do_versions_260(fd, lib, main);
blo_do_versions_270(fd, lib, main);
blo_do_versions_280(fd, lib, main);
+ blo_do_versions_290(fd, lib, main);
blo_do_versions_cycles(fd, lib, main);
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
@@ -10105,6 +10162,9 @@ static void lib_link_all(FileData *fd, Main *bmain)
case ID_AC:
lib_link_action(fd, bmain, (bAction *)id);
break;
+ case ID_SIM:
+ lib_link_simulation(fd, bmain, (Simulation *)id);
+ break;
case ID_IP:
/* XXX deprecated... still needs to be maintained for version patches still. */
lib_link_ipo(fd, bmain, (Ipo *)id);
@@ -10956,10 +11016,51 @@ static void expand_key(FileData *fd, Main *mainvar, Key *key)
expand_doit(fd, mainvar, key->ipo); // XXX deprecated - old animation system
}
+static void expand_node_socket(FileData *fd, Main *mainvar, bNodeSocket *sock)
+{
+ expand_idprops(fd, mainvar, sock->prop);
+
+ if (sock->default_value != NULL) {
+
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ expand_doit(fd, mainvar, default_value->value);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ expand_doit(fd, mainvar, default_value->value);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+ }
+}
+
+static void expand_node_sockets(FileData *fd, Main *mainvar, ListBase *sockets)
+{
+ LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
+ expand_node_socket(fd, mainvar, sock);
+ }
+}
+
static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
{
bNode *node;
- bNodeSocket *sock;
if (ntree->gpd) {
expand_doit(fd, mainvar, ntree->gpd);
@@ -10972,20 +11073,12 @@ static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
expand_idprops(fd, mainvar, node->prop);
- for (sock = node->inputs.first; sock; sock = sock->next) {
- expand_idprops(fd, mainvar, sock->prop);
- }
- for (sock = node->outputs.first; sock; sock = sock->next) {
- expand_idprops(fd, mainvar, sock->prop);
- }
+ expand_node_sockets(fd, mainvar, &node->inputs);
+ expand_node_sockets(fd, mainvar, &node->outputs);
}
- for (sock = ntree->inputs.first; sock; sock = sock->next) {
- expand_idprops(fd, mainvar, sock->prop);
- }
- for (sock = ntree->outputs.first; sock; sock = sock->next) {
- expand_idprops(fd, mainvar, sock->prop);
- }
+ expand_node_sockets(fd, mainvar, &ntree->inputs);
+ expand_node_sockets(fd, mainvar, &ntree->outputs);
}
static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
@@ -11536,6 +11629,13 @@ static void expand_volume(FileData *fd, Main *mainvar, Volume *volume)
}
}
+static void expand_simulation(FileData *fd, Main *mainvar, Simulation *simulation)
+{
+ if (simulation->adt) {
+ expand_animdata(fd, mainvar, simulation->adt);
+ }
+}
+
/**
* Set the callback func used over all ID data found by \a BLO_expand_main func.
*
@@ -11665,6 +11765,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_VO:
expand_volume(fd, mainvar, (Volume *)id);
break;
+ case ID_SIM:
+ expand_simulation(fd, mainvar, (Simulation *)id);
+ break;
default:
break;
}
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 80f8bfc3f07..55abbe703de 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -199,6 +199,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 *bmain);
void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *bmain);
+void blo_do_versions_290(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_cycles(struct FileData *fd, struct Library *lib, struct Main *bmain);
void do_versions_after_linking_250(struct Main *bmain);
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 98d2acbd938..989efa9a1db 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -55,7 +55,7 @@
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_colortools.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_modifier.h"
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index d246eadb381..1879ab10fef 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -75,6 +75,7 @@
#include "BKE_curveprofile.h"
#include "BKE_customdata.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
new file mode 100644
index 00000000000..0ce3cf405cd
--- /dev/null
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -0,0 +1,66 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup blenloader
+ */
+/* allow readfile to use deprecated functionality */
+#define DNA_DEPRECATED_ALLOW
+
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_genfile.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_collection.h"
+#include "BKE_main.h"
+
+#include "BLO_readfile.h"
+#include "readfile.h"
+
+/* Make preferences read-only, use versioning_userdef.c. */
+#define U (*((const UserDef *)&U))
+
+void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
+{
+ UNUSED_VARS(fd);
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SpaceImage", "float", "uv_opacity")) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+ sima->uv_opacity = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 8343895c8dd..f955f16a7ef 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -197,6 +197,7 @@ static void blo_update_defaults_screen(bScreen *screen,
v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
/* Remove dither pattern in wireframe mode. */
v3d->shading.xray_alpha_wire = 0.0f;
+ v3d->clip_start = 0.01f;
/* Skip startups that use the viewport color by default. */
if (v3d->shading.background_type != V3D_SHADING_BACKGROUND_VIEWPORT) {
copy_v3_fl(v3d->shading.background_color, 0.05f);
@@ -297,7 +298,7 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
/* Don't enable compositing nodes. */
if (scene->nodetree) {
- ntreeFreeNestedTree(scene->nodetree);
+ ntreeFreeEmbeddedTree(scene->nodetree);
MEM_freeN(scene->nodetree);
scene->nodetree = NULL;
scene->use_nodes = false;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 2b32621eb37..3015a0e1b8a 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -133,6 +133,7 @@
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
@@ -156,6 +157,7 @@
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h" // for G
#include "BKE_gpencil_modifier.h"
#include "BKE_idtype.h"
@@ -990,9 +992,19 @@ static void write_node_socket_default_value(WriteData *wd, bNodeSocket *sock)
case SOCK_STRING:
writestruct(wd, DATA, bNodeSocketValueString, 1, sock->default_value);
break;
+ case SOCK_OBJECT:
+ writestruct(wd, DATA, bNodeSocketValueObject, 1, sock->default_value);
+ break;
+ case SOCK_IMAGE:
+ writestruct(wd, DATA, bNodeSocketValueImage, 1, sock->default_value);
+ break;
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
BLI_assert(false);
break;
}
@@ -3854,6 +3866,24 @@ static void write_volume(WriteData *wd, Volume *volume, const void *id_address)
}
}
+static void write_simulation(WriteData *wd, Simulation *simulation)
+{
+ if (simulation->id.us > 0 || wd->use_memfile) {
+ writestruct(wd, ID_SIM, Simulation, 1, simulation);
+ write_iddata(wd, &simulation->id);
+
+ if (simulation->adt) {
+ write_animdata(wd, simulation->adt);
+ }
+
+ /* nodetree is integral part of simulation, no libdata */
+ if (simulation->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, simulation->nodetree);
+ write_nodetree_nolib(wd, simulation->nodetree);
+ }
+ }
+}
+
/* Keep it last of write_foodata functions. */
static void write_libraries(WriteData *wd, Main *main)
{
@@ -4203,6 +4233,9 @@ static bool write_file_handle(Main *mainvar,
case ID_VO:
write_volume(wd, (Volume *)id_buffer, id);
break;
+ case ID_SIM:
+ write_simulation(wd, (Simulation *)id);
+ break;
case ID_LI:
/* Do nothing, handled below - and should never be reached. */
BLI_assert(0);
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 74c46b1cf3e..5f6ae0a86e9 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -122,6 +122,7 @@ bool BLT_lang_is_ime_supported(void);
#define BLT_I18NCONTEXT_ID_IMAGE "Image"
/*#define BLT_I18NCONTEXT_ID_IPO "Ipo"*/ /* Deprecated */
#define BLT_I18NCONTEXT_ID_SHAPEKEY "Key"
+#define BLT_I18NCONTEXT_ID_SIMULATION "Simulation"
#define BLT_I18NCONTEXT_ID_LIGHT "Light"
#define BLT_I18NCONTEXT_ID_LIBRARY "Library"
#define BLT_I18NCONTEXT_ID_LATTICE "Lattice"
@@ -202,6 +203,7 @@ typedef struct {
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SCENE, "id_scene"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SCREEN, "id_screen"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SEQUENCE, "id_sequence"), \
+ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SIMULATION, "id_simulation"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SPEAKER, "id_speaker"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SOUND, "id_sound"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_TEXTURE, "id_texture"), \
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 4fa7bf64834..45666a21a2c 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1046,6 +1046,7 @@ static BMOpDefine bmo_extrude_face_region_def = {
{"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry (requires ``geom`` to include edges). */
{"use_normal_flip", BMO_OP_SLOT_BOOL}, /* Create faces with reversed direction. */
{"use_normal_from_adjacent", BMO_OP_SLOT_BOOL}, /* Use winding from surrounding faces instead of this region. */
+ {"use_dissolve_ortho_edges", BMO_OP_SLOT_BOOL}, /* Dissolve edges whose faces form a flat surface. */
{"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */
{{'\0'}},
},
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index 7a7f4a14db3..3c63f4a60d6 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -39,6 +39,7 @@ enum {
EXT_INPUT = 1,
EXT_KEEP = 2,
EXT_DEL = 4,
+ EXT_TAG = 8,
};
#define VERT_MARK 1
@@ -335,6 +336,8 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
const bool use_normal_from_adjacent = BMO_slot_bool_get(op->slots_in,
"use_normal_from_adjacent");
+ const bool use_dissolve_ortho_edges = BMO_slot_bool_get(op->slots_in,
+ "use_dissolve_ortho_edges");
/* initialize our sub-operators */
BMO_op_initf(bm,
@@ -442,6 +445,24 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
}
}
+ BMVert **dissolve_verts = NULL;
+ int dissolve_verts_len = 0;
+ float average_normal[3];
+ if (use_dissolve_ortho_edges) {
+ /* Calc average normal. */
+ zero_v3(average_normal);
+ BMO_ITER (f, &siter, dupeop.slots_out, "geom.out", BM_FACE) {
+ add_v3_v3(average_normal, f->no);
+ }
+ if (normalize_v3(average_normal) == 0.0f) {
+ average_normal[2] = 1.0f;
+ }
+
+ /* Allocate array to store possible vertices that will be dissolved. */
+ int boundary_verts_len = BMO_slot_map_count(dupeop.slots_out, "boundary_map.out");
+ dissolve_verts = MEM_mallocN((size_t)boundary_verts_len * sizeof(*dissolve_verts), __func__);
+ }
+
BMO_slot_copy(&dupeop, slots_out, "geom.out", op, slots_out, "geom.out");
slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude");
@@ -483,6 +504,16 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
continue;
}
+ BMFace *join_face = NULL;
+ if (use_dissolve_ortho_edges) {
+ if (BM_edge_is_boundary(e)) {
+ join_face = e->l->f;
+ if (fabs(dot_v3v3(average_normal, join_face->no)) > 0.0001f) {
+ join_face = NULL;
+ }
+ }
+ }
+
bool edge_normal_flip;
if (use_normal_from_adjacent == false) {
/* Orient loop to give same normal as a loop of 'e_new'
@@ -541,7 +572,22 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
#endif
- bm_extrude_copy_face_loop_attributes(bm, f);
+ if (join_face) {
+ BMVert *v1 = e->v1;
+ BMVert *v2 = e->v2;
+ if (!BMO_elem_flag_test(bm, v1, EXT_TAG)) {
+ BMO_elem_flag_enable(bm, v1, EXT_TAG);
+ dissolve_verts[dissolve_verts_len++] = v1;
+ }
+ if (!BMO_elem_flag_test(bm, v2, EXT_TAG)) {
+ BMO_elem_flag_enable(bm, v2, EXT_TAG);
+ dissolve_verts[dissolve_verts_len++] = v2;
+ }
+ bmesh_kernel_join_face_kill_edge(bm, join_face, f, e);
+ }
+ else {
+ bm_extrude_copy_face_loop_attributes(bm, f);
+ }
}
/* link isolated vert */
@@ -559,6 +605,23 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
BM_edge_create(bm, v, v2, NULL, BM_CREATE_NO_DOUBLE);
}
+ if (dissolve_verts) {
+ BMVert **v_iter = &dissolve_verts[0];
+ for (int i = dissolve_verts_len; i--; v_iter++) {
+ v = *v_iter;
+ e = v->e;
+ BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v);
+ if ((e_other == e) || (BM_DISK_EDGE_NEXT(e_other, v) == e)) {
+ /* Lose edge or BMVert is edge pair. */
+ BM_edge_collapse(bm, e, v, true, false);
+ }
+ else {
+ BLI_assert(!BM_vert_is_edge_pair(v));
+ }
+ }
+ MEM_freeN(dissolve_verts);
+ }
+
/* cleanup */
if (delorig) {
BMO_op_finish(bm, &delop);
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index bc127243836..d1ddceb00b0 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -997,10 +997,10 @@ static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1,
* record the change in offset_l (or offset_r); later we can tell that a change has happened
* because the offset will differ from its original value in offset_l_spec (or offset_r_spec).
*
- * \param edges_between If this is true, there are edges between e1 and e2 in CCW order so they
+ * \param edges_between: If this is true, there are edges between e1 and e2 in CCW order so they
* don't share a common face. We want the meeting point to be on an existing face so it
* should be dropped onto one of the intermediate faces, if possible.
- * \param e_in_plane If we need to drop from the calculated offset lines to one of the faces,
+ * \param e_in_plane: If we need to drop from the calculated offset lines to one of the faces,
* we don't want to drop onto the 'in plane' face, so if this is not null skip this edge's faces.
*/
static void offset_meet(EdgeHalf *e1,
@@ -2601,13 +2601,13 @@ static void adjust_miter_inner_coords(BevelParams *bp, BevVert *bv, EdgeHalf *em
* to be a subsequent pass to make the widths as consistent as possible.
* Doesn't make the actual BMVerts.
*
- * For a width consistency pass, we just recalculate the coordinates of the BoundVerts. If the
+ * For a width consistency pass, we just recalculate the coordinates of the #BoundVerts. If the
* other ends have been (re)built already, then we copy the offsets from there to match, else we
* use the ideal (user-specified) widths.
*
- * \param construct The first time through, construct will be true and we are making the BoundVerts
- * and setting up the BoundVert and EdgeHalf pointers appropriately. Also, if construct, decide on
- * the mesh pattern that will be used inside the boundary.
+ * \param construct: The first time through, construct will be true and we are making the
+ * #BoundVerts and setting up the #BoundVert and #EdgeHalf pointers appropriately.
+ * Also, if construct, decide on the mesh pattern that will be used inside the boundary.
*/
static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
{
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
index ec858ee2c19..fe2943419c5 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
@@ -50,7 +50,8 @@ void MovieDistortionOperation::initExecution()
full_frame.xmin = full_frame.ymin = 0;
full_frame.xmax = this->m_width;
full_frame.ymax = this->m_height;
- BKE_tracking_max_distortion_delta_across_bound(tracking, &full_frame, !this->m_apply, delta);
+ BKE_tracking_max_distortion_delta_across_bound(
+ tracking, this->m_width, this->m_height, &full_frame, !this->m_apply, delta);
/* 5 is just in case we didn't hit real max of distortion in
* BKE_tracking_max_undistortion_delta_across_bound
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index c94a8876ab0..d735d3b89bc 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -184,7 +184,7 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSce
/* Evaluation ----------------------------------- */
-bool DEG_is_evaluating(struct Depsgraph *depsgraph);
+bool DEG_is_evaluating(const struct Depsgraph *depsgraph);
bool DEG_is_active(const struct Depsgraph *depsgraph);
void DEG_make_active(struct Depsgraph *depsgraph);
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 26b46376a0a..3d570536223 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -111,14 +111,14 @@ struct ID *DEG_get_original_id(struct ID *id);
*
* Original IDs are considered all the IDs which are not covered by copy-on-write system and are
* not out-of-main localized data-blocks. */
-bool DEG_is_original_id(struct ID *id);
-bool DEG_is_original_object(struct Object *object);
+bool DEG_is_original_id(const struct ID *id);
+bool DEG_is_original_object(const struct Object *object);
/* Opposite of the above.
*
* If the data-block is not original it must be evaluated, and vice versa. */
-bool DEG_is_evaluated_id(struct ID *id);
-bool DEG_is_evaluated_object(struct Object *object);
+bool DEG_is_evaluated_id(const struct ID *id);
+bool DEG_is_evaluated_object(const struct Object *object);
/* Check whether depsgraph os fully evaluated. This includes the following checks:
* - Relations are up-to-date.
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index d880618753c..82f3ea7d182 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -31,7 +31,6 @@
#include "DNA_layer_types.h"
#include "DNA_object_types.h"
-#include "BLI_ghash.h"
#include "BLI_stack.h"
#include "BLI_utildefines.h"
@@ -157,10 +156,9 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
BLI_Stack *stack = BLI_stack_new(sizeof(OperationNode *), "DEG flush layers stack");
for (IDNode *id_node : graph->id_nodes) {
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (ComponentNode *comp_node : id_node->components.values()) {
comp_node->affects_directly_visible |= id_node->is_directly_visible;
}
- GHASH_FOREACH_END();
}
for (OperationNode *op_node : graph->operations) {
op_node->custom_flags = 0;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index f6834feeeae..10307df0dc4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -60,6 +60,7 @@ extern "C" {
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
@@ -74,7 +75,7 @@ extern "C" {
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_idprop.h"
@@ -120,20 +121,6 @@ extern "C" {
namespace DEG {
-namespace {
-
-void free_copy_on_write_datablock(void *id_info_v)
-{
- DepsgraphNodeBuilder::IDInfo *id_info = (DepsgraphNodeBuilder::IDInfo *)id_info_v;
- if (id_info->id_cow != nullptr) {
- deg_free_copy_on_write_datablock(id_info->id_cow);
- MEM_freeN(id_info->id_cow);
- }
- MEM_freeN(id_info);
-}
-
-} /* namespace */
-
/* ************ */
/* Node Builder */
@@ -147,15 +134,18 @@ DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain,
view_layer_(nullptr),
view_layer_index_(-1),
collection_(nullptr),
- is_parent_collection_visible_(true),
- id_info_hash_(nullptr)
+ is_parent_collection_visible_(true)
{
}
DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
{
- if (id_info_hash_ != nullptr) {
- BLI_ghash_free(id_info_hash_, nullptr, free_copy_on_write_datablock);
+ for (IDInfo *id_info : id_info_hash_.values()) {
+ if (id_info->id_cow != nullptr) {
+ deg_free_copy_on_write_datablock(id_info->id_cow);
+ MEM_freeN(id_info->id_cow);
+ }
+ MEM_freeN(id_info);
}
}
@@ -166,7 +156,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
IDComponentsMask previously_visible_components_mask = 0;
uint32_t previous_eval_flags = 0;
DEGCustomDataMeshMasks previous_customdata_masks;
- IDInfo *id_info = (IDInfo *)BLI_ghash_lookup(id_info_hash_, id);
+ IDInfo *id_info = id_info_hash_.lookup_default(id, nullptr);
if (id_info != nullptr) {
id_cow = id_info->id_cow;
previously_visible_components_mask = id_info->previously_visible_components_mask;
@@ -182,7 +172,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
/* Currently all ID nodes are supposed to have copy-on-write logic.
*
* NOTE: Zero number of components indicates that ID node was just created. */
- if (BLI_ghash_len(id_node->components) == 0) {
+ if (id_node->components.is_empty()) {
ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE);
OperationNode *op_cow = comp_cow->add_operation(
function_bind(deg_evaluate_copy_on_write, _1, id_node),
@@ -320,7 +310,6 @@ void DepsgraphNodeBuilder::begin_build()
{
/* Store existing copy-on-write versions of datablock, so we can re-use
* them for new ID nodes. */
- id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash");
for (IDNode *id_node : graph_->id_nodes) {
/* It is possible that the ID does not need to have CoW version in which case id_cow is the
* same as id_orig. Additionally, such ID might have been removed, which makes the check
@@ -344,11 +333,11 @@ void DepsgraphNodeBuilder::begin_build()
id_info->previously_visible_components_mask = id_node->visible_components_mask;
id_info->previous_eval_flags = id_node->eval_flags;
id_info->previous_customdata_masks = id_node->customdata_masks;
- BLI_ghash_insert(id_info_hash_, id_node->id_orig, id_info);
+ id_info_hash_.add_new(id_node->id_orig, id_info);
id_node->id_cow = nullptr;
}
- GSET_FOREACH_BEGIN (OperationNode *, op_node, graph_->entry_tags) {
+ for (OperationNode *op_node : graph_->entry_tags) {
ComponentNode *comp_node = op_node->owner;
IDNode *id_node = comp_node->owner;
@@ -360,12 +349,11 @@ void DepsgraphNodeBuilder::begin_build()
entry_tag.name_tag = op_node->name_tag;
saved_entry_tags_.push_back(entry_tag);
}
- GSET_FOREACH_END();
/* Make sure graph has no nodes left from previous state. */
graph_->clear_all_nodes();
graph_->operations.clear();
- BLI_gset_clear(graph_->entry_tags, nullptr);
+ graph_->entry_tags.clear();
}
void DepsgraphNodeBuilder::end_build()
@@ -482,6 +470,9 @@ void DepsgraphNodeBuilder::build_id(ID *id)
case ID_SCE:
build_scene_parameters((Scene *)id);
break;
+ case ID_SIM:
+ build_simulation((Simulation *)id);
+ break;
default:
fprintf(stderr, "Unhandled ID %s\n", id->name);
BLI_assert(!"Should never happen");
@@ -519,8 +510,7 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti
}
else if (from_layer_collection == nullptr && !id_node->is_collection_fully_expanded) {
/* Initially collection was built from layer now, and was requested
- * to not recurs into object. But nw it's asked to recurs into all
- * objects. */
+ * to not recurs into object. But now it's asked to recurs into all objects. */
}
else {
return;
@@ -1757,6 +1747,16 @@ void DepsgraphNodeBuilder::build_sound(bSound *sound)
build_parameters(&sound->id);
}
+void DepsgraphNodeBuilder::build_simulation(Simulation *simulation)
+{
+ if (built_map_.checkIsBuiltAndTag(simulation)) {
+ return;
+ }
+ add_id_node(&simulation->id);
+ build_animdata(&simulation->id);
+ build_parameters(&simulation->id);
+}
+
void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene)
{
if (scene->ed == nullptr) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 16beedabc2a..5cd7f7449a2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -37,7 +37,6 @@ struct Collection;
struct FCurve;
struct FreestyleLineSet;
struct FreestyleLineStyle;
-struct GHash;
struct ID;
struct IDProperty;
struct Image;
@@ -53,6 +52,7 @@ struct MovieClip;
struct Object;
struct ParticleSettings;
struct Scene;
+struct Simulation;
struct Speaker;
struct Tex;
struct World;
@@ -221,6 +221,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_lightprobe(LightProbe *probe);
virtual void build_speaker(Speaker *speaker);
virtual void build_sound(bSound *sound);
+ virtual void build_simulation(Simulation *simulation);
virtual void build_scene_sequencer(Scene *scene);
virtual void build_scene_audio(Scene *scene);
virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
@@ -279,7 +280,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
bool is_parent_collection_visible_;
/* Indexed by original ID, values are IDInfo. */
- GHash *id_info_hash_;
+ Map<const ID *, IDInfo *> id_info_hash_;
/* Set of IDs which were already build. Makes it easier to keep track of
* what was already built and what was not. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index ecacfcf7ee9..a0179181866 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -26,104 +26,55 @@
#include <stdio.h>
#include <string.h>
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
namespace DEG {
-static void free_rootpchanmap_valueset(void *val)
-{
- /* Just need to free the set itself - the names stored are all references. */
- GSet *values = (GSet *)val;
- BLI_gset_free(values, nullptr);
-}
-
RootPChanMap::RootPChanMap()
{
- /* Just create empty map. */
- map_ = BLI_ghash_str_new("RootPChanMap");
}
RootPChanMap::~RootPChanMap()
{
- /* Free the map, and all the value sets. */
- BLI_ghash_free(map_, nullptr, free_rootpchanmap_valueset);
}
/* Debug contents of map */
void RootPChanMap::print_debug()
{
- GHashIterator it1;
- GSetIterator it2;
-
- printf("Root PChan Map:\n");
- GHASH_ITER (it1, map_) {
- const char *item = (const char *)BLI_ghashIterator_getKey(&it1);
- GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1);
-
- printf(" %s : { ", item);
- GSET_ITER (it2, values) {
- const char *val = (const char *)BLI_gsetIterator_getKey(&it2);
- printf("%s, ", val);
+ map_.foreach_item([](StringRefNull key, const Set<StringRefNull> &values) {
+ printf(" %s : { ", key.data());
+ for (StringRefNull val : values) {
+ printf("%s, ", val.data());
}
printf("}\n");
- }
+ });
}
/* Add a mapping. */
void RootPChanMap::add_bone(const char *bone, const char *root)
{
- if (BLI_ghash_haskey(map_, bone)) {
- /* Add new entry, but only add the root if it doesn't already
- * exist in there. */
- GSet *values = (GSet *)BLI_ghash_lookup(map_, bone);
- BLI_gset_add(values, (void *)root);
- }
- else {
- /* Create new set and mapping. */
- GSet *values = BLI_gset_new(
- BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "RootPChanMap Value Set");
- BLI_ghash_insert(map_, (void *)bone, (void *)values);
-
- /* Add new entry now. */
- BLI_gset_insert(values, (void *)root);
- }
+ map_.lookup_or_add_default(bone).add(root);
}
/* Check if there's a common root bone between two bones. */
bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) const
{
- /* Ensure that both are in the map... */
- if (BLI_ghash_haskey(map_, bone1) == false) {
+ const Set<StringRefNull> *bone1_roots = map_.lookup_ptr(bone1);
+ const Set<StringRefNull> *bone2_roots = map_.lookup_ptr(bone2);
+
+ if (bone1_roots == nullptr) {
// fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2);
// print_debug();
return false;
}
- if (BLI_ghash_haskey(map_, bone2) == false) {
+ if (bone2_roots == nullptr) {
// fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2);
// print_debug();
return false;
}
- GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1);
- GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2);
-
- GSetIterator it1, it2;
- GSET_ITER (it1, bone1_roots) {
- GSET_ITER (it2, bone2_roots) {
- const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1);
- const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2);
-
- if (strcmp(v1, v2) == 0) {
- // fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2);
- return true;
- }
- }
- }
-
- // fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2);
- return false;
+ return Set<StringRefNull>::Intersects(*bone1_roots, *bone2_roots);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
index 1442f547b08..c3c90e5aae4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
@@ -23,7 +23,7 @@
#pragma once
-struct GHash;
+#include "intern/depsgraph_type.h"
namespace DEG {
@@ -42,13 +42,11 @@ struct RootPChanMap {
bool has_common_root(const char *bone1, const char *bone2) const;
protected:
- /* The actual map:
- * - Keys are "strings" (const char *) - not dynamically allocated.
- * - Values are "sets" (const char *) - not dynamically allocated.
- *
- * We don't use the C++ maps here, as it's more convenient to use
- * Blender's GHash and be able to compare by-value instead of by-ref. */
- struct GHash *map_;
+ /**
+ * The strings are only referenced by this map. Users of RootPChanMap have to make sure that the
+ * life-time of the strings is long enough.
+ */
+ Map<StringRefNull, Set<StringRefNull>> map_;
};
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 552546ff094..7a1df5bcb27 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -28,7 +28,6 @@
#include <cstring> /* required for STREQ later on. */
#include <stdio.h>
#include <stdlib.h>
-#include <unordered_set>
#include "MEM_guardedalloc.h"
@@ -62,6 +61,7 @@ extern "C" {
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
@@ -76,7 +76,7 @@ extern "C" {
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
@@ -122,8 +122,6 @@ extern "C" {
namespace DEG {
-using std::unordered_set;
-
/* ***************** */
/* Relations Builder */
@@ -559,6 +557,9 @@ void DepsgraphRelationBuilder::build_id(ID *id)
case ID_SCE:
build_scene_parameters((Scene *)id);
break;
+ case ID_SIM:
+ build_simulation((Simulation *)id);
+ break;
default:
fprintf(stderr, "Unhandled ID %s\n", id->name);
BLI_assert(!"Should never happen");
@@ -2399,22 +2400,28 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
return;
}
/* texture itself */
+ ComponentKey texture_key(&texture->id, NodeType::GENERIC_DATABLOCK);
build_idproperties(texture->id.properties);
build_animdata(&texture->id);
build_parameters(&texture->id);
+
/* texture's nodetree */
build_nodetree(texture->nodetree);
+ build_nested_nodetree(&texture->id, texture->nodetree);
+
/* Special cases for different IDs which texture uses. */
if (texture->type == TEX_IMAGE) {
if (texture->ima != nullptr) {
build_image(texture->ima);
+
+ ComponentKey image_key(&texture->ima->id, NodeType::GENERIC_DATABLOCK);
+ add_relation(image_key, texture_key, "Texture Image");
}
}
- build_nested_nodetree(&texture->id, texture->nodetree);
+
if (check_id_has_anim_component(&texture->id)) {
ComponentKey animation_key(&texture->id, NodeType::ANIMATION);
- ComponentKey datablock_key(&texture->id, NodeType::GENERIC_DATABLOCK);
- add_relation(animation_key, datablock_key, "Datablock Animation");
+ add_relation(animation_key, texture_key, "Datablock Animation");
}
}
@@ -2565,6 +2572,15 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound)
build_parameters(&sound->id);
}
+void DepsgraphRelationBuilder::build_simulation(Simulation *simulation)
+{
+ if (built_map_.checkIsBuiltAndTag(simulation)) {
+ return;
+ }
+ build_animdata(&simulation->id);
+ build_parameters(&simulation->id);
+}
+
void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
{
if (scene->ed == nullptr) {
@@ -2680,7 +2696,7 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
Node *node_cow = find_node(copy_on_write_key);
OperationNode *op_cow = node_cow->get_exit_operation();
/* Plug any other components to this one. */
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (ComponentNode *comp_node : id_node->components.values()) {
if (comp_node->type == NodeType::COPY_ON_WRITE) {
/* Copy-on-write component never depends on itself. */
continue;
@@ -2723,11 +2739,11 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
rel->flag |= rel_flag;
}
/* All dangling operations should also be executed after copy-on-write. */
- GHASH_FOREACH_BEGIN (OperationNode *, op_node, comp_node->operations_map) {
+ for (OperationNode *op_node : comp_node->operations_map->values()) {
if (op_node == op_entry) {
continue;
}
- if (op_node->inlinks.size() == 0) {
+ if (op_node->inlinks.is_empty()) {
Relation *rel = graph_->add_new_relation(op_cow, op_node, "CoW Dependency");
rel->flag |= rel_flag;
}
@@ -2749,7 +2765,6 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
}
}
}
- GHASH_FOREACH_END();
/* NOTE: We currently ignore implicit relations to an external
* data-blocks for copy-on-write operations. This means, for example,
* copy-on-write component of Object will not wait for copy-on-write
@@ -2758,7 +2773,6 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
* evaluation step needs geometry, it will have transitive dependency
* to Mesh copy-on-write already. */
}
- GHASH_FOREACH_END();
/* TODO(sergey): This solves crash for now, but causes too many
* updates potentially. */
if (GS(id_orig->name) == ID_OB) {
@@ -2807,7 +2821,7 @@ static bool is_reachable(const Node *const from, const Node *const to)
// Perform a graph walk from 'to' towards its incoming connections.
// Walking from 'from' towards its outgoing connections is 10x slower on the Spring rig.
deque<const Node *> queue;
- unordered_set<const Node *> seen;
+ Set<const Node *> seen;
queue.push_back(to);
while (!queue.empty()) {
// Visit the next node to inspect.
@@ -2821,7 +2835,7 @@ static bool is_reachable(const Node *const from, const Node *const to)
// Queue all incoming relations that we haven't seen before.
for (Relation *relation : visit->inlinks) {
const Node *prev_node = relation->from;
- if (seen.insert(prev_node).second) {
+ if (seen.add(prev_node)) {
queue.push_back(prev_node);
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 3c9bd8a9856..aa6d8ababd3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -69,6 +69,7 @@ struct Object;
struct ParticleSettings;
struct ParticleSystem;
struct Scene;
+struct Simulation;
struct Speaker;
struct Tex;
struct ViewLayer;
@@ -286,6 +287,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_lightprobe(LightProbe *probe);
virtual void build_speaker(Speaker *speaker);
virtual void build_sound(bSound *sound);
+ virtual void build_simulation(Simulation *simulation);
virtual void build_scene_sequencer(Scene *scene);
virtual void build_scene_audio(Scene *scene);
virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index ff2bc2ac3ea..b75252aa325 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -69,7 +69,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
RootPChanMap *root_map)
{
if ((con->flag & CONSTRAINT_DISABLE) != 0) {
- /* Do not add disabled IK constraints to the relations. If these needs to be temporarly
+ /* Do not add disabled IK constraints to the relations. If these needs to be temporarily
* enabled, they will be added as temporary constraints during transform. */
return;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc
index 2ce1f1f1c1d..c6545362bb1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc
@@ -43,7 +43,7 @@ static inline bool is_unused_noop(OperationNode *op_node)
if (op_node->flag & OperationFlag::DEPSOP_FLAG_PINNED) {
return false;
}
- return op_node->is_noop() && op_node->outlinks.empty();
+ return op_node->is_noop() && op_node->outlinks.is_empty();
}
void deg_graph_remove_unused_noops(Depsgraph *graph)
@@ -61,7 +61,7 @@ void deg_graph_remove_unused_noops(Depsgraph *graph)
OperationNode *to_remove = queue.front();
queue.pop_front();
- while (!to_remove->inlinks.empty()) {
+ while (!to_remove->inlinks.is_empty()) {
Relation *rel_in = to_remove->inlinks[0];
Node *dependency = rel_in->from;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 73f6730be03..a35b69df60d 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -27,7 +27,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -57,37 +56,33 @@ namespace DEG {
class RNANodeQueryIDData {
public:
- explicit RNANodeQueryIDData(const ID *id) : id_(id), contraint_to_pchan_map_(nullptr)
+ explicit RNANodeQueryIDData(const ID *id) : id_(id), constraint_to_pchan_map_(nullptr)
{
}
~RNANodeQueryIDData()
{
- if (contraint_to_pchan_map_ != nullptr) {
- BLI_ghash_free(contraint_to_pchan_map_, nullptr, nullptr);
- }
+ delete constraint_to_pchan_map_;
}
const bPoseChannel *get_pchan_for_constraint(const bConstraint *constraint)
{
ensure_constraint_to_pchan_map();
- return static_cast<bPoseChannel *>(BLI_ghash_lookup(contraint_to_pchan_map_, constraint));
+ return constraint_to_pchan_map_->lookup_default(constraint, nullptr);
}
void ensure_constraint_to_pchan_map()
{
- if (contraint_to_pchan_map_ != nullptr) {
+ if (constraint_to_pchan_map_ != nullptr) {
return;
}
BLI_assert(GS(id_->name) == ID_OB);
const Object *object = reinterpret_cast<const Object *>(id_);
- contraint_to_pchan_map_ = BLI_ghash_ptr_new("id data pchan constraint map");
+ constraint_to_pchan_map_ = new Map<const bConstraint *, const bPoseChannel *>();
if (object->pose != nullptr) {
LISTBASE_FOREACH (const bPoseChannel *, pchan, &object->pose->chanbase) {
LISTBASE_FOREACH (const bConstraint *, constraint, &pchan->constraints) {
- BLI_ghash_insert(contraint_to_pchan_map_,
- const_cast<bConstraint *>(constraint),
- const_cast<bPoseChannel *>(pchan));
+ constraint_to_pchan_map_->add_new(constraint, pchan);
}
}
}
@@ -99,7 +94,7 @@ class RNANodeQueryIDData {
/* indexed by bConstraint*, returns pose channel which contains that
* constraint. */
- GHash *contraint_to_pchan_map_;
+ Map<const bConstraint *, const bPoseChannel *> *constraint_to_pchan_map_;
};
/* ***************************** Node Identifier **************************** */
@@ -121,26 +116,13 @@ bool RNANodeIdentifier::is_valid() const
/* ********************************** Query ********************************* */
-namespace {
-
-void ghash_id_data_free_func(void *value)
-{
- RNANodeQueryIDData *id_data = static_cast<RNANodeQueryIDData *>(value);
- OBJECT_GUARDED_DELETE(id_data, RNANodeQueryIDData);
-}
-
-} // namespace
-
RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph, DepsgraphBuilder *builder)
- : depsgraph_(depsgraph),
- builder_(builder),
- id_data_map_(BLI_ghash_ptr_new("rna node query id data hash"))
+ : depsgraph_(depsgraph), builder_(builder)
{
}
RNANodeQuery::~RNANodeQuery()
{
- BLI_ghash_free(id_data_map_, nullptr, ghash_id_data_free_func);
}
Node *RNANodeQuery::find_node(const PointerRNA *ptr,
@@ -384,12 +366,9 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
RNANodeQueryIDData *RNANodeQuery::ensure_id_data(const ID *id)
{
- RNANodeQueryIDData **id_data_ptr;
- if (!BLI_ghash_ensure_p(
- id_data_map_, const_cast<ID *>(id), reinterpret_cast<void ***>(&id_data_ptr))) {
- *id_data_ptr = OBJECT_GUARDED_NEW(RNANodeQueryIDData, id);
- }
- return *id_data_ptr;
+ unique_ptr<RNANodeQueryIDData> &id_data = id_data_map_.lookup_or_add(
+ id, [&]() { return BLI::make_unique<RNANodeQueryIDData>(id); });
+ return id_data.get();
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h
index 8a79d9abef9..bd806ce058a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h
@@ -26,7 +26,6 @@
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_operation.h"
-struct GHash;
struct ID;
struct PointerRNA;
struct PropertyRNA;
@@ -83,7 +82,7 @@ class RNANodeQuery {
DepsgraphBuilder *builder_;
/* Indexed by an ID, returns RNANodeQueryIDData associated with that ID. */
- GHash *id_data_map_;
+ Map<const ID *, unique_ptr<RNANodeQueryIDData>> id_data_map_;
/* Construct identifier of the node which corresponds given configuration
* of RNA property. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 3f828ef5bb0..22ceac899b8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -72,6 +72,8 @@ static void deg_graph_tag_paths_recursive(Node *node)
void deg_graph_transitive_reduction(Depsgraph *graph)
{
int num_removed_relations = 0;
+ Vector<Relation *> relations_to_remove;
+
for (OperationNode *target : graph->operations) {
/* Clear tags. */
for (OperationNode *node : graph->operations) {
@@ -85,25 +87,24 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
deg_graph_tag_paths_recursive(rel->from);
}
/* Remove redundant paths to the target. */
- for (Node::Relations::const_iterator it_rel = target->inlinks.begin();
- it_rel != target->inlinks.end();) {
- Relation *rel = *it_rel;
+ for (Relation *rel : target->inlinks) {
if (rel->from->type == NodeType::TIMESOURCE) {
/* HACK: time source nodes don't get "custom_flags" flag
* set/cleared. */
/* TODO: there will be other types in future, so iterators above
* need modifying. */
- ++it_rel;
+ continue;
}
else if (rel->from->custom_flags & OP_REACHABLE) {
- rel->unlink();
- OBJECT_GUARDED_DELETE(rel, Relation);
- num_removed_relations++;
- }
- else {
- ++it_rel;
+ relations_to_remove.append(rel);
}
}
+ for (Relation *rel : relations_to_remove) {
+ rel->unlink();
+ OBJECT_GUARDED_DELETE(rel, Relation);
+ }
+ num_removed_relations += relations_to_remove.size();
+ relations_to_remove.clear();
}
DEG_DEBUG_PRINTF((::Depsgraph *)graph, BUILD, "Removed %d relations\n", num_removed_relations);
}
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 7080f8a1a9b..14a095fdb8e 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -25,7 +25,6 @@
#include <cstdarg>
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
extern "C" {
@@ -407,15 +406,14 @@ static void deg_debug_graphviz_node(const DebugContext &ctx, const Node *node)
switch (node->type) {
case NodeType::ID_REF: {
const IDNode *id_node = (const IDNode *)node;
- if (BLI_ghash_len(id_node->components) == 0) {
+ if (id_node->components.is_empty()) {
deg_debug_graphviz_node_single(ctx, node);
}
else {
deg_debug_graphviz_node_cluster_begin(ctx, node);
- GHASH_FOREACH_BEGIN (const ComponentNode *, comp, id_node->components) {
+ for (const ComponentNode *comp : id_node->components.values()) {
deg_debug_graphviz_node(ctx, comp);
}
- GHASH_FOREACH_END();
deg_debug_graphviz_node_cluster_end(ctx);
}
break;
@@ -472,7 +470,7 @@ static bool deg_debug_graphviz_is_cluster(const Node *node)
switch (node->type) {
case NodeType::ID_REF: {
const IDNode *id_node = (const IDNode *)node;
- return BLI_ghash_len(id_node->components) > 0;
+ return !id_node->components.is_empty();
}
case NodeType::PARAMETERS:
case NodeType::ANIMATION:
@@ -568,12 +566,11 @@ static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, const Depsgr
static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, const Depsgraph *graph)
{
for (IDNode *id_node : graph->id_nodes) {
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (ComponentNode *comp_node : id_node->components.values()) {
for (OperationNode *op_node : comp_node->operations) {
deg_debug_graphviz_node_relations(ctx, op_node);
}
}
- GHASH_FOREACH_END();
}
TimeSourceNode *time_source = graph->find_time_source();
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 6d88782d68c..faf375155b5 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -31,7 +31,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_console.h"
-#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_utildefines.h"
@@ -60,12 +59,6 @@ extern "C" {
namespace DEG {
-/* TODO(sergey): Find a better place for this. */
-template<typename T> static void remove_from_vector(vector<T> *vector, const T &value)
-{
- vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end());
-}
-
Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
: time_source(nullptr),
need_update(true),
@@ -81,8 +74,6 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
is_render_pipeline_depsgraph(false)
{
BLI_spin_init(&lock);
- id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
- entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags");
memset(id_type_updated, 0, sizeof(id_type_updated));
memset(id_type_exist, 0, sizeof(id_type_exist));
memset(physics_relations, 0, sizeof(physics_relations));
@@ -91,8 +82,6 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
Depsgraph::~Depsgraph()
{
clear_id_nodes();
- BLI_ghash_free(id_hash, nullptr, nullptr);
- BLI_gset_free(entry_tags, nullptr);
if (time_source != nullptr) {
OBJECT_GUARDED_DELETE(time_source, TimeSourceNode);
}
@@ -117,7 +106,7 @@ TimeSourceNode *Depsgraph::find_time_source() const
IDNode *Depsgraph::find_id_node(const ID *id) const
{
- return reinterpret_cast<IDNode *>(BLI_ghash_lookup(id_hash, id));
+ return id_hash.lookup_default(id, nullptr);
}
IDNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint)
@@ -132,7 +121,7 @@ IDNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint)
*
* NOTE: We address ID nodes by the original ID pointer they are
* referencing to. */
- BLI_ghash_insert(id_hash, id, id_node);
+ id_hash.add_new(id, id_node);
id_nodes.push_back(id_node);
id_type_exist[BKE_idtype_idcode_to_index(GS(id->name))] = 1;
@@ -170,7 +159,7 @@ void Depsgraph::clear_id_nodes()
OBJECT_GUARDED_DELETE(id_node, IDNode);
}
/* Clear containers. */
- BLI_ghash_clear(id_hash, nullptr, nullptr);
+ id_hash.clear();
id_nodes.clear();
/* Clear physics relation caches. */
clear_physics_relations(this);
@@ -233,7 +222,7 @@ void Depsgraph::add_entry_tag(OperationNode *node)
* from.
* NOTE: this is necessary since we have several thousand nodes to play
* with. */
- BLI_gset_insert(entry_tags, node);
+ entry_tags.add(node);
}
void Depsgraph::clear_all_nodes()
@@ -320,9 +309,9 @@ void DEG_graph_free(Depsgraph *graph)
OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph);
}
-bool DEG_is_evaluating(struct Depsgraph *depsgraph)
+bool DEG_is_evaluating(const struct Depsgraph *depsgraph)
{
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph);
return deg_graph->is_evaluating;
}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 7801f95e008..672f202338e 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -43,8 +43,6 @@
#include "intern/debug/deg_debug.h"
#include "intern/depsgraph_type.h"
-struct GHash;
-struct GSet;
struct ID;
struct Scene;
struct ViewLayer;
@@ -97,7 +95,7 @@ struct Depsgraph {
/* <ID : IDNode> mapping from ID blocks to nodes representing these
* blocks, used for quick lookups. */
- GHash *id_hash;
+ Map<const ID *, IDNode *> id_hash;
/* Ordered list of ID nodes, order matches ID allocation order.
* Used for faster iteration, especially for areas which are critical to
@@ -119,7 +117,7 @@ struct Depsgraph {
/* Quick-Access Temp Data ............. */
/* Nodes which have been tagged as "directly modified". */
- GSet *entry_tags;
+ Set<OperationNode *> entry_tags;
/* Special entry tag for time source. Allows to tag invisible dependency graphs for update when
* scene frame changes, so then when dependency graph becomes visible it is on a proper state. */
@@ -169,7 +167,7 @@ struct Depsgraph {
/* Cached list of colliders/effectors for collections and the scene
* created along with relations, for fast lookup during evaluation. */
- GHash *physics_relations[DEG_PHYSICS_RELATIONS_NUM];
+ Map<const ID *, ListBase *> *physics_relations[DEG_PHYSICS_RELATIONS_NUM];
};
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index d78bc07ac5e..59065ea671a 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -25,7 +25,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index c713a4a3fb1..8b6984c9870 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -23,7 +23,6 @@
* Implementation of tools for debugging the depsgraph
*/
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
extern "C" {
@@ -224,13 +223,12 @@ void DEG_stats_simple(const Depsgraph *graph,
for (DEG::IDNode *id_node : deg_graph->id_nodes) {
tot_outer++;
- GHASH_FOREACH_BEGIN (DEG::ComponentNode *, comp_node, id_node->components) {
+ for (DEG::ComponentNode *comp_node : id_node->components.values()) {
tot_outer++;
for (DEG::OperationNode *op_node : comp_node->operations) {
tot_rels += op_node->inlinks.size();
}
}
- GHASH_FOREACH_END();
}
DEG::TimeSourceNode *time_source = deg_graph->find_time_source();
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 9251d975125..c5628a4f8b9 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -25,7 +25,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -87,5 +86,5 @@ void DEG_evaluate_on_framechange(Main *bmain, Depsgraph *graph, float ctime)
bool DEG_needs_eval(Depsgraph *graph)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
- return BLI_gset_len(deg_graph->entry_tags) != 0 || deg_graph->need_update_time;
+ return !deg_graph->entry_tags.is_empty() || deg_graph->need_update_time;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc
index d7c09780845..20375e447c3 100644
--- a/source/blender/depsgraph/intern/depsgraph_physics.cc
+++ b/source/blender/depsgraph/intern/depsgraph_physics.cc
@@ -28,7 +28,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_compiler_compat.h"
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
extern "C" {
@@ -72,8 +71,8 @@ ListBase *DEG_get_effector_relations(const Depsgraph *graph, Collection *collect
}
ID *collection_orig = DEG_get_original_id(&collection->id);
- return (ListBase *)BLI_ghash_lookup(deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR],
- collection_orig);
+ return deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR]->lookup_default(collection_orig,
+ nullptr);
}
ListBase *DEG_get_collision_relations(const Depsgraph *graph,
@@ -86,7 +85,7 @@ ListBase *DEG_get_collision_relations(const Depsgraph *graph,
return nullptr;
}
ID *collection_orig = DEG_get_original_id(&collection->id);
- return (ListBase *)BLI_ghash_lookup(deg_graph->physics_relations[type], collection_orig);
+ return deg_graph->physics_relations[type]->lookup_default(collection_orig, nullptr);
}
/********************** Depsgraph Building API ************************/
@@ -165,19 +164,15 @@ namespace DEG {
ListBase *build_effector_relations(Depsgraph *graph, Collection *collection)
{
- GHash *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR];
+ Map<const ID *, ListBase *> *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR];
if (hash == nullptr) {
- graph->physics_relations[DEG_PHYSICS_EFFECTOR] = BLI_ghash_ptr_new(
- "Depsgraph physics relations hash");
+ graph->physics_relations[DEG_PHYSICS_EFFECTOR] = new Map<const ID *, ListBase *>();
hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR];
}
- ListBase *relations = reinterpret_cast<ListBase *>(BLI_ghash_lookup(hash, collection));
- if (relations == nullptr) {
+ return hash->lookup_or_add(&collection->id, [&]() {
::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph);
- relations = BKE_effector_relations_create(depsgraph, graph->view_layer, collection);
- BLI_ghash_insert(hash, &collection->id, relations);
- }
- return relations;
+ return BKE_effector_relations_create(depsgraph, graph->view_layer, collection);
+ });
}
ListBase *build_collision_relations(Depsgraph *graph,
@@ -185,48 +180,38 @@ ListBase *build_collision_relations(Depsgraph *graph,
unsigned int modifier_type)
{
const ePhysicsRelationType type = modifier_to_relation_type(modifier_type);
- GHash *hash = graph->physics_relations[type];
+ Map<const ID *, ListBase *> *hash = graph->physics_relations[type];
if (hash == nullptr) {
- graph->physics_relations[type] = BLI_ghash_ptr_new("Depsgraph physics relations hash");
+ graph->physics_relations[type] = new Map<const ID *, ListBase *>();
hash = graph->physics_relations[type];
}
- ListBase *relations = reinterpret_cast<ListBase *>(BLI_ghash_lookup(hash, collection));
- if (relations == nullptr) {
+ return hash->lookup_or_add(&collection->id, [&]() {
::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph);
- relations = BKE_collision_relations_create(depsgraph, collection, modifier_type);
- BLI_ghash_insert(hash, &collection->id, relations);
- }
- return relations;
-}
-
-namespace {
-
-void free_effector_relations(void *value)
-{
- BKE_effector_relations_free(reinterpret_cast<ListBase *>(value));
+ return BKE_collision_relations_create(depsgraph, collection, modifier_type);
+ });
}
-void free_collision_relations(void *value)
-{
- BKE_collision_relations_free(reinterpret_cast<ListBase *>(value));
-}
-
-} // namespace
-
void clear_physics_relations(Depsgraph *graph)
{
for (int i = 0; i < DEG_PHYSICS_RELATIONS_NUM; i++) {
- if (graph->physics_relations[i]) {
+ Map<const ID *, ListBase *> *hash = graph->physics_relations[i];
+ if (hash) {
const ePhysicsRelationType type = (ePhysicsRelationType)i;
switch (type) {
case DEG_PHYSICS_EFFECTOR:
- BLI_ghash_free(graph->physics_relations[i], nullptr, free_effector_relations);
+ for (ListBase *list : hash->values()) {
+ BKE_effector_relations_free(list);
+ }
+ hash->clear();
break;
case DEG_PHYSICS_COLLISION:
case DEG_PHYSICS_SMOKE_COLLISION:
case DEG_PHYSICS_DYNAMIC_BRUSH:
- BLI_ghash_free(graph->physics_relations[i], nullptr, free_collision_relations);
+ for (ListBase *list : hash->values()) {
+ BKE_collision_relations_free(list);
+ }
+ hash->clear();
break;
case DEG_PHYSICS_RELATIONS_NUM:
break;
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 6e85b2e8bd9..b64b6c0e715 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -28,7 +28,6 @@
extern "C" {
#include <string.h> // XXX: memcpy
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -271,7 +270,7 @@ ID *DEG_get_original_id(ID *id)
return (ID *)id->orig_id;
}
-bool DEG_is_original_id(ID *id)
+bool DEG_is_original_id(const ID *id)
{
/* Some explanation of the logic.
*
@@ -296,17 +295,17 @@ bool DEG_is_original_id(ID *id)
return true;
}
-bool DEG_is_original_object(Object *object)
+bool DEG_is_original_object(const Object *object)
{
return DEG_is_original_id(&object->id);
}
-bool DEG_is_evaluated_id(ID *id)
+bool DEG_is_evaluated_id(const ID *id)
{
return !DEG_is_original_id(id);
}
-bool DEG_is_evaluated_object(Object *object)
+bool DEG_is_evaluated_object(const Object *object)
{
return !DEG_is_original_object(object);
}
@@ -319,7 +318,7 @@ bool DEG_is_fully_evaluated(const struct Depsgraph *depsgraph)
return false;
}
/* Check whether IDs are up to date. */
- if (BLI_gset_len(deg_graph->entry_tags) > 0) {
+ if (!deg_graph->entry_tags.is_empty()) {
return false;
}
return true;
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index efd7d6e77ef..b68c4b91fcc 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -23,14 +23,9 @@
* Implementation of Querying and Filtering API's
*/
-#include <unordered_set>
-
#include "MEM_guardedalloc.h"
-extern "C" {
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
-} /* extern "C" */
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -50,8 +45,6 @@ extern "C" {
namespace DEG {
namespace {
-using std::unordered_set;
-
typedef deque<OperationNode *> TraversalQueue;
typedef void (*DEGForeachOperation)(OperationNode *op_node, void *user_data);
@@ -66,11 +59,12 @@ bool deg_foreach_needs_visit(const OperationNode *op_node, const int flags)
return true;
}
-static void deg_foreach_dependent_operation(const IDNode *target_id_node,
- eDepsObjectComponentType source_component_type,
- int flags,
- DEGForeachOperation callback,
- void *user_data)
+void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph),
+ const IDNode *target_id_node,
+ eDepsObjectComponentType source_component_type,
+ int flags,
+ DEGForeachOperation callback,
+ void *user_data)
{
if (target_id_node == nullptr) {
/* TODO(sergey): Shall we inform or assert here about attempt to start
@@ -79,8 +73,8 @@ static void deg_foreach_dependent_operation(const IDNode *target_id_node,
}
/* Start with scheduling all operations from ID node. */
TraversalQueue queue;
- unordered_set<OperationNode *> scheduled;
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, target_id_node->components) {
+ Set<OperationNode *> scheduled;
+ for (ComponentNode *comp_node : target_id_node->components.values()) {
if (source_component_type != DEG_OB_COMP_ANY &&
nodeTypeToObjectComponent(comp_node->type) != source_component_type) {
continue;
@@ -90,10 +84,9 @@ static void deg_foreach_dependent_operation(const IDNode *target_id_node,
continue;
}
queue.push_back(op_node);
- scheduled.insert(op_node);
+ scheduled.add(op_node);
}
}
- GHASH_FOREACH_END();
/* Process the queue. */
while (!queue.empty()) {
/* get next operation node to process. */
@@ -104,9 +97,8 @@ static void deg_foreach_dependent_operation(const IDNode *target_id_node,
/* Schedule outgoing operation nodes. */
if (op_node->outlinks.size() == 1) {
OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to;
- if (scheduled.find(to_node) == scheduled.end() &&
- deg_foreach_needs_visit(to_node, flags)) {
- scheduled.insert(to_node);
+ if (!scheduled.contains(to_node) && deg_foreach_needs_visit(to_node, flags)) {
+ scheduled.add_new(to_node);
op_node = to_node;
}
else {
@@ -116,10 +108,9 @@ static void deg_foreach_dependent_operation(const IDNode *target_id_node,
else {
for (Relation *rel : op_node->outlinks) {
OperationNode *to_node = (OperationNode *)rel->to;
- if (scheduled.find(to_node) == scheduled.end() &&
- deg_foreach_needs_visit(to_node, flags)) {
+ if (!scheduled.contains(to_node) && deg_foreach_needs_visit(to_node, flags)) {
queue.push_front(to_node);
- scheduled.insert(to_node);
+ scheduled.add_new(to_node);
}
}
break;
@@ -132,7 +123,7 @@ struct ForeachIDComponentData {
DEGForeachIDComponentCallback callback;
void *user_data;
IDNode *target_id_node;
- unordered_set<ComponentNode *> visited;
+ Set<ComponentNode *> visited;
};
void deg_foreach_dependent_component_callback(OperationNode *op_node, void *user_data_v)
@@ -140,11 +131,10 @@ void deg_foreach_dependent_component_callback(OperationNode *op_node, void *user
ForeachIDComponentData *user_data = reinterpret_cast<ForeachIDComponentData *>(user_data_v);
ComponentNode *comp_node = op_node->owner;
IDNode *id_node = comp_node->owner;
- if (id_node != user_data->target_id_node &&
- user_data->visited.find(comp_node) == user_data->visited.end()) {
+ if (id_node != user_data->target_id_node && !user_data->visited.contains(comp_node)) {
user_data->callback(
id_node->id_orig, nodeTypeToObjectComponent(comp_node->type), user_data->user_data);
- user_data->visited.insert(comp_node);
+ user_data->visited.add_new(comp_node);
}
}
@@ -159,7 +149,8 @@ void deg_foreach_dependent_ID_component(const Depsgraph *graph,
data.callback = callback;
data.user_data = user_data;
data.target_id_node = graph->find_id_node(id);
- deg_foreach_dependent_operation(data.target_id_node,
+ deg_foreach_dependent_operation(graph,
+ data.target_id_node,
source_component_type,
flags,
deg_foreach_dependent_component_callback,
@@ -170,7 +161,7 @@ struct ForeachIDData {
DEGForeachIDCallback callback;
void *user_data;
IDNode *target_id_node;
- unordered_set<IDNode *> visited;
+ Set<IDNode *> visited;
};
void deg_foreach_dependent_ID_callback(OperationNode *op_node, void *user_data_v)
@@ -178,10 +169,9 @@ void deg_foreach_dependent_ID_callback(OperationNode *op_node, void *user_data_v
ForeachIDData *user_data = reinterpret_cast<ForeachIDData *>(user_data_v);
ComponentNode *comp_node = op_node->owner;
IDNode *id_node = comp_node->owner;
- if (id_node != user_data->target_id_node &&
- user_data->visited.find(id_node) == user_data->visited.end()) {
+ if (id_node != user_data->target_id_node && !user_data->visited.contains(id_node)) {
user_data->callback(id_node->id_orig, user_data->user_data);
- user_data->visited.insert(id_node);
+ user_data->visited.add_new(id_node);
}
}
@@ -195,7 +185,7 @@ void deg_foreach_dependent_ID(const Depsgraph *graph,
data.user_data = user_data;
data.target_id_node = graph->find_id_node(id);
deg_foreach_dependent_operation(
- data.target_id_node, DEG_OB_COMP_ANY, 0, deg_foreach_dependent_ID_callback, &data);
+ graph, data.target_id_node, DEG_OB_COMP_ANY, 0, deg_foreach_dependent_ID_callback, &data);
}
void deg_foreach_ancestor_ID(const Depsgraph *graph,
@@ -212,16 +202,15 @@ void deg_foreach_ancestor_ID(const Depsgraph *graph,
}
/* Start with scheduling all operations from ID node. */
TraversalQueue queue;
- unordered_set<OperationNode *> scheduled;
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, target_id_node->components) {
+ Set<OperationNode *> scheduled;
+ for (ComponentNode *comp_node : target_id_node->components.values()) {
for (OperationNode *op_node : comp_node->operations) {
queue.push_back(op_node);
- scheduled.insert(op_node);
+ scheduled.add(op_node);
}
}
- GHASH_FOREACH_END();
- unordered_set<IDNode *> visited;
- visited.insert(target_id_node);
+ Set<IDNode *> visited;
+ visited.add_new(target_id_node);
/* Process the queue. */
while (!queue.empty()) {
/* get next operation node to process. */
@@ -231,18 +220,17 @@ void deg_foreach_ancestor_ID(const Depsgraph *graph,
/* Check whether we need to inform callee about corresponding ID node. */
ComponentNode *comp_node = op_node->owner;
IDNode *id_node = comp_node->owner;
- if (visited.find(id_node) == visited.end()) {
+ if (!visited.contains(id_node)) {
/* TODO(sergey): Is it orig or CoW? */
callback(id_node->id_orig, user_data);
- visited.insert(id_node);
+ visited.add_new(id_node);
}
/* Schedule incoming operation nodes. */
if (op_node->inlinks.size() == 1) {
Node *from = op_node->inlinks[0]->from;
if (from->get_class() == NodeClass::OPERATION) {
OperationNode *from_node = (OperationNode *)from;
- if (scheduled.find(from_node) == scheduled.end()) {
- scheduled.insert(from_node);
+ if (scheduled.add(from_node)) {
op_node = from_node;
}
else {
@@ -255,9 +243,8 @@ void deg_foreach_ancestor_ID(const Depsgraph *graph,
Node *from = rel->from;
if (from->get_class() == NodeClass::OPERATION) {
OperationNode *from_node = (OperationNode *)from;
- if (scheduled.find(from_node) == scheduled.end()) {
+ if (scheduled.add(from_node)) {
queue.push_front(from_node);
- scheduled.insert(from_node);
}
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_registry.cc b/source/blender/depsgraph/intern/depsgraph_registry.cc
index ad60b1bc4cf..3b0a0b3ea19 100644
--- a/source/blender/depsgraph/intern/depsgraph_registry.cc
+++ b/source/blender/depsgraph/intern/depsgraph_registry.cc
@@ -29,46 +29,33 @@
namespace DEG {
-typedef set<Depsgraph *> DepsgraphStorage;
-typedef map<Main *, DepsgraphStorage> MainDepsgraphMap;
-
-static MainDepsgraphMap g_graph_registry;
+static Map<Main *, VectorSet<Depsgraph *>> g_graph_registry;
void register_graph(Depsgraph *depsgraph)
{
Main *bmain = depsgraph->bmain;
- MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
- if (it == g_graph_registry.end()) {
- it = g_graph_registry.insert(make_pair(bmain, DepsgraphStorage())).first;
- }
- DepsgraphStorage &storage = it->second;
- storage.insert(depsgraph);
+ g_graph_registry.lookup_or_add_default(bmain).add_new(depsgraph);
}
void unregister_graph(Depsgraph *depsgraph)
{
Main *bmain = depsgraph->bmain;
- MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
- BLI_assert(it != g_graph_registry.end());
-
- // Remove dependency graph from storage.
- DepsgraphStorage &storage = it->second;
- storage.erase(depsgraph);
+ VectorSet<Depsgraph *> &graphs = g_graph_registry.lookup(bmain);
+ graphs.remove(depsgraph);
// If this was the last depsgraph associated with the main, remove the main entry as well.
- if (storage.empty()) {
- g_graph_registry.erase(bmain);
+ if (graphs.is_empty()) {
+ g_graph_registry.remove(bmain);
}
}
-const set<Depsgraph *> &get_all_registered_graphs(Main *bmain)
+ArrayRef<Depsgraph *> get_all_registered_graphs(Main *bmain)
{
- MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
- if (it == g_graph_registry.end()) {
- static DepsgraphStorage empty_storage;
- return empty_storage;
+ VectorSet<Depsgraph *> *graphs = g_graph_registry.lookup_ptr(bmain);
+ if (graphs != nullptr) {
+ return *graphs;
}
- return it->second;
+ return {};
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_registry.h b/source/blender/depsgraph/intern/depsgraph_registry.h
index 7517b6a0b2a..f8e5b9543f2 100644
--- a/source/blender/depsgraph/intern/depsgraph_registry.h
+++ b/source/blender/depsgraph/intern/depsgraph_registry.h
@@ -33,6 +33,6 @@ struct Depsgraph;
void register_graph(Depsgraph *depsgraph);
void unregister_graph(Depsgraph *depsgraph);
-const set<Depsgraph *> &get_all_registered_graphs(Main *bmain);
+ArrayRef<Depsgraph *> get_all_registered_graphs(Main *bmain);
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_relation.cc b/source/blender/depsgraph/intern/depsgraph_relation.cc
index cff62540ca8..a4ec48658f5 100644
--- a/source/blender/depsgraph/intern/depsgraph_relation.cc
+++ b/source/blender/depsgraph/intern/depsgraph_relation.cc
@@ -30,12 +30,6 @@
namespace DEG {
-/* TODO(sergey): Find a better place for this. */
-template<typename T> static void remove_from_vector(vector<T> *vector, const T &value)
-{
- vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end());
-}
-
Relation::Relation(Node *from, Node *to, const char *description)
: from(from), to(to), name(description), flag(0)
{
@@ -52,8 +46,8 @@ Relation::Relation(Node *from, Node *to, const char *description)
*
* - Un-registering relation is not a cheap operation, so better to have it
* as an explicit call if we need this. */
- from->outlinks.push_back(this);
- to->inlinks.push_back(this);
+ from->outlinks.append(this);
+ to->inlinks.append(this);
}
Relation::~Relation()
@@ -66,8 +60,8 @@ void Relation::unlink()
{
/* Sanity check. */
BLI_assert(from != nullptr && to != nullptr);
- remove_from_vector(&from->outlinks, this);
- remove_from_vector(&to->inlinks, this);
+ from->outlinks.remove_first_occurrence_and_reorder(this);
+ to->inlinks.remove_first_occurrence_and_reorder(this);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 1c56808ea82..ff7d9ee0170 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -495,13 +495,13 @@ void deg_graph_node_tag_zero(Main *bmain,
ID *id = id_node->id_orig;
/* TODO(sergey): Which recalc flags to set here? */
id_node->id_cow->recalc |= deg_recalc_flags_for_legacy_zero();
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+
+ for (ComponentNode *comp_node : id_node->components.values()) {
if (comp_node->type == NodeType::ANIMATION) {
continue;
}
comp_node->tag_update(graph, update_source);
}
- GHASH_FOREACH_END();
deg_graph_id_tag_legacy_compat(bmain, graph, id, (IDRecalcFlag)0, update_source);
}
diff --git a/source/blender/depsgraph/intern/depsgraph_type.cc b/source/blender/depsgraph/intern/depsgraph_type.cc
index 559bf8dfdab..92d775b0ae4 100644
--- a/source/blender/depsgraph/intern/depsgraph_type.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type.cc
@@ -25,7 +25,6 @@
#include <cstdlib> // for BLI_assert()
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
#include "DNA_customdata_types.h"
diff --git a/source/blender/depsgraph/intern/depsgraph_type.h b/source/blender/depsgraph/intern/depsgraph_type.h
index fbf5c2fd381..7016d07ae72 100644
--- a/source/blender/depsgraph/intern/depsgraph_type.h
+++ b/source/blender/depsgraph/intern/depsgraph_type.h
@@ -38,9 +38,14 @@
#include <map>
#include <set>
#include <string>
-#include <unordered_map>
#include <vector>
+#include "BLI_map.hh"
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
+
struct Depsgraph;
struct CustomData_MeshMasks;
@@ -48,12 +53,19 @@ struct CustomData_MeshMasks;
namespace DEG {
/* Commonly used types. */
+using BLI::ArrayRef;
+using BLI::Map;
+using BLI::Set;
+using BLI::StringRef;
+using BLI::StringRefNull;
+using BLI::Vector;
+using BLI::VectorSet;
using std::deque;
using std::map;
using std::pair;
using std::set;
using std::string;
-using std::unordered_map;
+using std::unique_ptr;
using std::vector;
/* Commonly used functions. */
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index c7f3c5cb2b6..189beb506b3 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -28,7 +28,6 @@
#include "PIL_time.h"
#include "BLI_compiler_attrs.h"
-#include "BLI_ghash.h"
#include "BLI_gsqueue.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -61,18 +60,17 @@ namespace {
struct DepsgraphEvalState;
-void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id);
+void deg_task_run_func(TaskPool *pool, void *taskdata);
template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
void schedule_children(DepsgraphEvalState *state,
OperationNode *node,
- const int thread_id,
ScheduleFunction *schedule_function,
ScheduleFunctionArgs... schedule_function_args);
-void schedule_node_to_pool(OperationNode *node, const int thread_id, TaskPool *pool)
+void schedule_node_to_pool(OperationNode *node, const int UNUSED(thread_id), TaskPool *pool)
{
- BLI_task_pool_push_from_thread(pool, deg_task_run_func, node, false, NULL, thread_id);
+ BLI_task_pool_push(pool, deg_task_run_func, node, false, NULL);
}
/* Denotes which part of dependency graph is being evaluated. */
@@ -116,9 +114,9 @@ void evaluate_node(const DepsgraphEvalState *state, OperationNode *operation_nod
}
}
-void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id)
+void deg_task_run_func(TaskPool *pool, void *taskdata)
{
- void *userdata_v = BLI_task_pool_userdata(pool);
+ void *userdata_v = BLI_task_pool_user_data(pool);
DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v;
/* Evaluate node. */
@@ -126,9 +124,7 @@ void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id)
evaluate_node(state, operation_node);
/* Schedule children. */
- BLI_task_pool_delayed_push_begin(pool, thread_id);
- schedule_children(state, operation_node, thread_id, schedule_node_to_pool, pool);
- BLI_task_pool_delayed_push_end(pool, thread_id);
+ schedule_children(state, operation_node, schedule_node_to_pool, pool);
}
bool check_operation_node_visible(OperationNode *op_node)
@@ -238,7 +234,6 @@ template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
void schedule_node(DepsgraphEvalState *state,
OperationNode *node,
bool dec_parents,
- const int thread_id,
ScheduleFunction *schedule_function,
ScheduleFunctionArgs... schedule_function_args)
{
@@ -271,11 +266,11 @@ void schedule_node(DepsgraphEvalState *state,
if (!is_scheduled) {
if (node->is_noop()) {
/* skip NOOP node, schedule children right away */
- schedule_children(state, node, thread_id, schedule_function, schedule_function_args...);
+ schedule_children(state, node, schedule_function, schedule_function_args...);
}
else {
/* children are scheduled once this task is completed */
- schedule_function(node, thread_id, schedule_function_args...);
+ schedule_function(node, 0, schedule_function_args...);
}
}
}
@@ -286,14 +281,13 @@ void schedule_graph(DepsgraphEvalState *state,
ScheduleFunctionArgs... schedule_function_args)
{
for (OperationNode *node : state->graph->operations) {
- schedule_node(state, node, false, -1, schedule_function, schedule_function_args...);
+ schedule_node(state, node, false, schedule_function, schedule_function_args...);
}
}
template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
void schedule_children(DepsgraphEvalState *state,
OperationNode *node,
- const int thread_id,
ScheduleFunction *schedule_function,
ScheduleFunctionArgs... schedule_function_args)
{
@@ -307,7 +301,6 @@ void schedule_children(DepsgraphEvalState *state,
schedule_node(state,
child,
(rel->flag & RELATION_FLAG_CYCLIC) == 0,
- thread_id,
schedule_function,
schedule_function_args...);
}
@@ -330,7 +323,7 @@ void evaluate_graph_single_threaded(DepsgraphEvalState *state)
BLI_gsqueue_pop(evaluation_queue, &operation_node);
evaluate_node(state, operation_node);
- schedule_children(state, operation_node, 0, schedule_node_to_queue, evaluation_queue);
+ schedule_children(state, operation_node, schedule_node_to_queue, evaluation_queue);
}
BLI_gsqueue_free(evaluation_queue);
@@ -354,6 +347,16 @@ void depsgraph_ensure_view_layer(Depsgraph *graph)
} // namespace
+static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ return BLI_task_pool_create_no_threads(state);
+ }
+ else {
+ return BLI_task_pool_create_suspended(state, TASK_PRIORITY_HIGH);
+ }
+}
+
/**
* Evaluate all nodes tagged for updating,
* \warning This is usually done as part of main loop, but may also be
@@ -364,7 +367,7 @@ void depsgraph_ensure_view_layer(Depsgraph *graph)
void deg_evaluate_on_refresh(Depsgraph *graph)
{
/* Nothing to update, early out. */
- if (BLI_gset_len(graph->entry_tags) == 0) {
+ if (graph->entry_tags.is_empty()) {
return;
}
@@ -377,30 +380,20 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
state.graph = graph;
state.do_stats = graph->debug.do_time_debug();
state.need_single_thread_pass = false;
- /* Set up task scheduler and pull for threaded evaluation. */
- TaskScheduler *task_scheduler;
- bool need_free_scheduler;
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- task_scheduler = BLI_task_scheduler_create(1);
- need_free_scheduler = true;
- }
- else {
- task_scheduler = BLI_task_scheduler_get();
- need_free_scheduler = false;
- }
- TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state, TASK_PRIORITY_HIGH);
/* Prepare all nodes for evaluation. */
initialize_execution(&state, graph);
/* Do actual evaluation now. */
-
/* First, process all Copy-On-Write nodes. */
state.stage = EvaluationStage::COPY_ON_WRITE;
+ TaskPool *task_pool = deg_evaluate_task_pool_create(&state);
schedule_graph(&state, schedule_node_to_pool, task_pool);
- BLI_task_pool_work_wait_and_reset(task_pool);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
/* After that, process all other nodes. */
state.stage = EvaluationStage::THREADED_EVALUATION;
+ task_pool = deg_evaluate_task_pool_create(&state);
schedule_graph(&state, schedule_node_to_pool, task_pool);
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
@@ -418,9 +411,6 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
}
/* Clear any uncleared tags - just in case. */
deg_graph_clear_tags(graph);
- if (need_free_scheduler) {
- BLI_task_scheduler_free(task_scheduler);
- }
graph->is_evaluating = false;
graph->debug.end_graph_evaluation();
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index 990002cf2e8..5ff1b31b07c 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -27,7 +27,6 @@
#include <cmath>
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_task.h"
@@ -94,9 +93,9 @@ void flush_init_id_node_func(void *__restrict data_v,
Depsgraph *graph = (Depsgraph *)data_v;
IDNode *id_node = graph->id_nodes[i];
id_node->custom_flags = ID_STATE_NONE;
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components)
+ for (ComponentNode *comp_node : id_node->components.values()) {
comp_node->custom_flags = COMPONENT_STATE_NONE;
- GHASH_FOREACH_END();
+ }
}
BLI_INLINE void flush_prepare(Depsgraph *graph)
@@ -116,7 +115,7 @@ BLI_INLINE void flush_prepare(Depsgraph *graph)
BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue)
{
- GSET_FOREACH_BEGIN (OperationNode *, op_node, graph->entry_tags) {
+ for (OperationNode *op_node : graph->entry_tags) {
queue->push_back(op_node);
op_node->scheduled = true;
DEG_DEBUG_PRINTF((::Depsgraph *)graph,
@@ -124,7 +123,6 @@ BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue)
"Operation is entry point for update: %s\n",
op_node->identifier().c_str());
}
- GSET_FOREACH_END();
}
BLI_INLINE void flush_handle_id_node(IDNode *id_node)
@@ -231,7 +229,7 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd
ID *id_orig = id_node->id_orig;
ID *id_cow = id_node->id_cow;
/* Gather recalc flags from all changed components. */
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (DEG::ComponentNode *comp_node : id_node->components.values()) {
if (comp_node->custom_flags != COMPONENT_STATE_DONE) {
continue;
}
@@ -239,7 +237,6 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd
BLI_assert(factory != nullptr);
id_cow->recalc |= factory->id_recalc_tag();
}
- GHASH_FOREACH_END();
DEG_DEBUG_PRINTF((::Depsgraph *)graph,
EVAL,
"Accumulated recalc bits for %s: %u\n",
@@ -307,7 +304,7 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph)
if (!deg_copy_on_write_is_expanded(id_cow)) {
continue;
}
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (ComponentNode *comp_node : id_node->components.values()) {
if (comp_node->custom_flags != COMPONENT_STATE_DONE) {
continue;
}
@@ -322,7 +319,6 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph)
break;
}
}
- GHASH_FOREACH_END();
}
#else
(void)graph;
@@ -347,7 +343,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
graph->ctime = ctime;
time_source->tag_update(graph, DEG::DEG_UPDATE_SOURCE_TIME);
}
- if (BLI_gset_len(graph->entry_tags) == 0) {
+ if (graph->entry_tags.is_empty()) {
return;
}
/* Reset all flags, get ready for the flush. */
@@ -393,7 +389,7 @@ void deg_graph_clear_tags(Depsgraph *graph)
DEPSOP_FLAG_USER_MODIFIED);
}
/* Clear any entry tags which haven't been flushed. */
- BLI_gset_clear(graph->entry_tags, nullptr);
+ graph->entry_tags.clear();
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc
index f164560ac24..9d3b1356570 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc
@@ -23,7 +23,6 @@
#include "intern/eval/deg_eval_stats.h"
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
#include "intern/depsgraph.h"
@@ -41,10 +40,9 @@ void deg_eval_stats_aggregate(Depsgraph *graph)
* Those are not filled in by the evaluation engine. */
for (Node *node : graph->id_nodes) {
IDNode *id_node = (IDNode *)node;
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (ComponentNode *comp_node : id_node->components.values()) {
comp_node->stats.reset_current();
}
- GHASH_FOREACH_END();
id_node->stats.reset_current();
}
/* Now accumulate operation timings to components and IDs. */
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index ffa37341ea6..ad1eba2f7ba 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -163,7 +163,7 @@ struct Node {
* The reason why all depsgraph nodes are descended from this type (apart
* from basic serialization benefits - from the typeinfo) is that we can
* have relationships between these nodes. */
- typedef vector<Relation *> Relations;
+ typedef Vector<Relation *> Relations;
string name; /* Identifier - mainly for debugging purposes. */
NodeType type; /* Structural type of node. */
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc
index 54796b8965b..9c142cdc97b 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_component.cc
@@ -26,7 +26,6 @@
#include <cstring> /* required for STREQ later on. */
#include <stdio.h>
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
extern "C" {
@@ -72,41 +71,10 @@ bool ComponentNode::OperationIDKey::operator==(const OperationIDKey &other) cons
return (opcode == other.opcode) && (STREQ(name, other.name)) && (name_tag == other.name_tag);
}
-static unsigned int comp_node_hash_key(const void *key_v)
-{
- const ComponentNode::OperationIDKey *key =
- reinterpret_cast<const ComponentNode::OperationIDKey *>(key_v);
- int opcode_as_int = static_cast<int>(key->opcode);
- return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(opcode_as_int),
- BLI_ghashutil_strhash_p(key->name));
-}
-
-static bool comp_node_hash_key_cmp(const void *a, const void *b)
-{
- const ComponentNode::OperationIDKey *key_a =
- reinterpret_cast<const ComponentNode::OperationIDKey *>(a);
- const ComponentNode::OperationIDKey *key_b =
- reinterpret_cast<const ComponentNode::OperationIDKey *>(b);
- return !(*key_a == *key_b);
-}
-
-static void comp_node_hash_key_free(void *key_v)
-{
- typedef ComponentNode::OperationIDKey OperationIDKey;
- OperationIDKey *key = reinterpret_cast<OperationIDKey *>(key_v);
- OBJECT_GUARDED_DELETE(key, OperationIDKey);
-}
-
-static void comp_node_hash_value_free(void *value_v)
-{
- OperationNode *op_node = reinterpret_cast<OperationNode *>(value_v);
- OBJECT_GUARDED_DELETE(op_node, OperationNode);
-}
-
ComponentNode::ComponentNode()
: entry_operation(nullptr), exit_operation(nullptr), affects_directly_visible(false)
{
- operations_map = BLI_ghash_new(comp_node_hash_key, comp_node_hash_key_cmp, "Depsgraph id hash");
+ operations_map = new Map<ComponentNode::OperationIDKey, OperationNode *>();
}
/* Initialize 'component' node - from pointer data given */
@@ -121,7 +89,7 @@ ComponentNode::~ComponentNode()
{
clear_operations();
if (operations_map != nullptr) {
- BLI_ghash_free(operations_map, comp_node_hash_key_free, comp_node_hash_value_free);
+ delete operations_map;
}
}
@@ -137,7 +105,7 @@ OperationNode *ComponentNode::find_operation(OperationIDKey key) const
{
OperationNode *node = nullptr;
if (operations_map != nullptr) {
- node = (OperationNode *)BLI_ghash_lookup(operations_map, &key);
+ node = operations_map->lookup_default(key, nullptr);
}
else {
for (OperationNode *op_node : operations) {
@@ -203,8 +171,8 @@ OperationNode *ComponentNode::add_operation(const DepsEvalOperationCb &op,
op_node = (OperationNode *)factory->create_node(this->owner->id_orig, "", name);
/* register opnode in this component's operation set */
- OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name, name_tag);
- BLI_ghash_insert(operations_map, key, op_node);
+ OperationIDKey key(opcode, name, name_tag);
+ operations_map->add(key, op_node);
/* set backlink */
op_node->owner = this;
@@ -242,7 +210,10 @@ void ComponentNode::set_exit_operation(OperationNode *op_node)
void ComponentNode::clear_operations()
{
if (operations_map != nullptr) {
- BLI_ghash_clear(operations_map, comp_node_hash_key_free, comp_node_hash_value_free);
+ for (OperationNode *op_node : operations_map->values()) {
+ OBJECT_GUARDED_DELETE(op_node, OperationNode);
+ }
+ operations_map->clear();
}
for (OperationNode *op_node : operations) {
OBJECT_GUARDED_DELETE(op_node, OperationNode);
@@ -261,10 +232,9 @@ void ComponentNode::tag_update(Depsgraph *graph, eUpdateSource source)
}
// It is possible that tag happens before finalization.
if (operations_map != nullptr) {
- GHASH_FOREACH_BEGIN (OperationNode *, op_node, operations_map) {
+ for (OperationNode *op_node : operations_map->values()) {
op_node->tag_update(graph, source);
}
- GHASH_FOREACH_END();
}
}
@@ -273,13 +243,12 @@ OperationNode *ComponentNode::get_entry_operation()
if (entry_operation) {
return entry_operation;
}
- else if (operations_map != nullptr && BLI_ghash_len(operations_map) == 1) {
+ else if (operations_map != nullptr && operations_map->size() == 1) {
OperationNode *op_node = nullptr;
/* TODO(sergey): This is somewhat slow. */
- GHASH_FOREACH_BEGIN (OperationNode *, tmp, operations_map) {
+ for (OperationNode *tmp : operations_map->values()) {
op_node = tmp;
}
- GHASH_FOREACH_END();
/* Cache for the subsequent usage. */
entry_operation = op_node;
return op_node;
@@ -295,13 +264,12 @@ OperationNode *ComponentNode::get_exit_operation()
if (exit_operation) {
return exit_operation;
}
- else if (operations_map != nullptr && BLI_ghash_len(operations_map) == 1) {
+ else if (operations_map != nullptr && operations_map->size() == 1) {
OperationNode *op_node = nullptr;
/* TODO(sergey): This is somewhat slow. */
- GHASH_FOREACH_BEGIN (OperationNode *, tmp, operations_map) {
+ for (OperationNode *tmp : operations_map->values()) {
op_node = tmp;
}
- GHASH_FOREACH_END();
/* Cache for the subsequent usage. */
exit_operation = op_node;
return op_node;
@@ -314,12 +282,11 @@ OperationNode *ComponentNode::get_exit_operation()
void ComponentNode::finalize_build(Depsgraph * /*graph*/)
{
- operations.reserve(BLI_ghash_len(operations_map));
- GHASH_FOREACH_BEGIN (OperationNode *, op_node, operations_map) {
+ operations.reserve(operations_map->size());
+ for (OperationNode *op_node : operations_map->values()) {
operations.push_back(op_node);
}
- GHASH_FOREACH_END();
- BLI_ghash_free(operations_map, comp_node_hash_key_free, nullptr);
+ delete operations_map;
operations_map = nullptr;
}
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index 38ea4005a72..41d5c130ffd 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -26,10 +26,11 @@
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_operation.h"
+#include "BLI_ghash.h"
+#include "BLI_hash.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
-struct GHash;
struct ID;
struct bPoseChannel;
@@ -115,7 +116,7 @@ struct ComponentNode : public Node {
/* Operations stored as a hash map, for faster build.
* This hash map will be freed when graph is fully built. */
- GHash *operations_map;
+ Map<ComponentNode::OperationIDKey, OperationNode *> *operations_map;
/* This is a "normal" list of operations, used by evaluation
* and other routines after construction. */
@@ -203,3 +204,18 @@ struct BoneComponentNode : public ComponentNode {
void deg_register_component_depsnodes();
} // namespace DEG
+
+namespace BLI {
+
+template<> struct DefaultHash<DEG::ComponentNode::OperationIDKey> {
+ uint32_t operator()(const DEG::ComponentNode::OperationIDKey &key) const
+ {
+ const int opcode_as_int = static_cast<int>(key.opcode);
+ return BLI_ghashutil_combine_hash(
+ key.name_tag,
+ BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(opcode_as_int),
+ BLI_ghashutil_strhash_p(key.name)));
+ }
+};
+
+} // namespace BLI
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc
index 4b6120a6985..4e998fb095a 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_id.cc
@@ -26,7 +26,6 @@
#include <cstring> /* required for STREQ later on. */
#include <stdio.h>
-#include "BLI_ghash.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -69,34 +68,6 @@ bool IDNode::ComponentIDKey::operator==(const ComponentIDKey &other) const
return type == other.type && STREQ(name, other.name);
}
-static unsigned int id_deps_node_hash_key(const void *key_v)
-{
- const IDNode::ComponentIDKey *key = reinterpret_cast<const IDNode::ComponentIDKey *>(key_v);
- const int type_as_int = static_cast<int>(key->type);
- return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(type_as_int),
- BLI_ghashutil_strhash_p(key->name));
-}
-
-static bool id_deps_node_hash_key_cmp(const void *a, const void *b)
-{
- const IDNode::ComponentIDKey *key_a = reinterpret_cast<const IDNode::ComponentIDKey *>(a);
- const IDNode::ComponentIDKey *key_b = reinterpret_cast<const IDNode::ComponentIDKey *>(b);
- return !(*key_a == *key_b);
-}
-
-static void id_deps_node_hash_key_free(void *key_v)
-{
- typedef IDNode::ComponentIDKey ComponentIDKey;
- ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v);
- OBJECT_GUARDED_DELETE(key, ComponentIDKey);
-}
-
-static void id_deps_node_hash_value_free(void *value_v)
-{
- ComponentNode *comp_node = reinterpret_cast<ComponentNode *>(value_v);
- OBJECT_GUARDED_DELETE(comp_node, ComponentNode);
-}
-
/* Initialize 'id' node - from pointer data given. */
void IDNode::init(const ID *id, const char *UNUSED(subdata))
{
@@ -116,9 +87,6 @@ void IDNode::init(const ID *id, const char *UNUSED(subdata))
visible_components_mask = 0;
previously_visible_components_mask = 0;
-
- components = BLI_ghash_new(
- id_deps_node_hash_key, id_deps_node_hash_key_cmp, "Depsgraph id components hash");
}
void IDNode::init_copy_on_write(ID *id_cow_hint)
@@ -158,7 +126,9 @@ void IDNode::destroy()
return;
}
- BLI_ghash_free(components, id_deps_node_hash_key_free, id_deps_node_hash_value_free);
+ for (ComponentNode *comp_node : components.values()) {
+ OBJECT_GUARDED_DELETE(comp_node, ComponentNode);
+ }
/* Free memory used by this CoW ID. */
if (id_cow != id_orig && id_cow != nullptr) {
@@ -185,7 +155,7 @@ string IDNode::identifier() const
ComponentNode *IDNode::find_component(NodeType type, const char *name) const
{
ComponentIDKey key(type, name);
- return reinterpret_cast<ComponentNode *>(BLI_ghash_lookup(components, &key));
+ return components.lookup_default(key, nullptr);
}
ComponentNode *IDNode::add_component(NodeType type, const char *name)
@@ -196,8 +166,8 @@ ComponentNode *IDNode::add_component(NodeType type, const char *name)
comp_node = (ComponentNode *)factory->create_node(this->id_orig, "", name);
/* Register. */
- ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name);
- BLI_ghash_insert(components, key, comp_node);
+ ComponentIDKey key(type, name);
+ components.add_new(key, comp_node);
comp_node->owner = this;
}
return comp_node;
@@ -205,7 +175,7 @@ ComponentNode *IDNode::add_component(NodeType type, const char *name)
void IDNode::tag_update(Depsgraph *graph, eUpdateSource source)
{
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) {
+ for (ComponentNode *comp_node : components.values()) {
/* Relations update does explicit animation update when needed. Here we ignore animation
* component to avoid loss of possible unkeyed changes. */
if (comp_node->type == NodeType::ANIMATION && source == DEG_UPDATE_SOURCE_RELATIONS) {
@@ -213,30 +183,27 @@ void IDNode::tag_update(Depsgraph *graph, eUpdateSource source)
}
comp_node->tag_update(graph, source);
}
- GHASH_FOREACH_END();
}
void IDNode::finalize_build(Depsgraph *graph)
{
/* Finalize build of all components. */
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) {
+ for (ComponentNode *comp_node : components.values()) {
comp_node->finalize_build(graph);
}
- GHASH_FOREACH_END();
visible_components_mask = get_visible_components_mask();
}
IDComponentsMask IDNode::get_visible_components_mask() const
{
IDComponentsMask result = 0;
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) {
+ for (ComponentNode *comp_node : components.values()) {
if (comp_node->affects_directly_visible) {
const int component_type_as_int = static_cast<int>(comp_node->type);
BLI_assert(component_type_as_int < 64);
result |= (1ULL << component_type_as_int);
}
}
- GHASH_FOREACH_END();
return result;
}
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h
index 80bb67f182f..c7663b50c6f 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.h
+++ b/source/blender/depsgraph/intern/node/deg_node_id.h
@@ -23,12 +23,11 @@
#pragma once
+#include "BLI_ghash.h"
#include "BLI_sys_types.h"
#include "DNA_ID.h"
#include "intern/node/deg_node.h"
-struct GHash;
-
namespace DEG {
struct ComponentNode;
@@ -82,7 +81,7 @@ struct IDNode : public Node {
ID *id_cow;
/* Hash to make it faster to look up components. */
- GHash *components;
+ Map<ComponentIDKey, ComponentNode *> components;
/* Additional flags needed for scene evaluation.
* TODO(sergey): Only needed for until really granular updates
@@ -116,3 +115,16 @@ struct IDNode : public Node {
};
} // namespace DEG
+
+namespace BLI {
+
+template<> struct DefaultHash<DEG::IDNode::ComponentIDKey> {
+ uint32_t operator()(const DEG::IDNode::ComponentIDKey &key) const
+ {
+ const int type_as_int = static_cast<int>(key.type);
+ return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(type_as_int),
+ BLI_ghashutil_strhash_p(key.name));
+ }
+};
+
+} // namespace BLI
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index 1e03d51f557..d327e1da8a1 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -25,7 +25,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
#include "intern/depsgraph.h"
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 1bdc3bc5a03..6e7654aed02 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -77,7 +77,7 @@ typedef bool (*DRW_SelectPassFn)(eDRWSelectStage stage, void *user_data);
typedef bool (*DRW_ObjectFilterFn)(struct Object *ob, void *user_data);
void DRW_draw_view(const struct bContext *C);
-void DRW_draw_region_engine_info(int xoffset, int yoffset);
+void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height);
void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index 13927cd5124..a6e6b30a6b1 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -73,8 +73,7 @@ static void eevee_motion_blur_camera_get_matrix_at_time(Scene *scene,
/* Past matrix */
/* FIXME : This is a temporal solution that does not take care of parent animations */
/* Recalc Anim manually */
- BKE_animsys_evaluate_animdata(
- scene, &camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL, false);
+ BKE_animsys_evaluate_animdata(&camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL, false);
BKE_object_where_is_calc_time(draw_ctx->depsgraph, scene, &cam_cpy, time);
/* Compute winmat */
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index 40687306b4e..401f5c76a02 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -4509,7 +4509,7 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
}
}
-static void extract_run(TaskPool *__restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void extract_run(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
ExtractTaskData *data = taskdata;
mesh_extract_iter(
@@ -4595,7 +4595,7 @@ static void extract_task_create(TaskPool *task_pool,
else {
/* Single threaded extraction. */
(*task_counter)++;
- extract_run(NULL, taskdata, -1);
+ extract_run(NULL, taskdata);
MEM_freeN(taskdata);
}
}
@@ -4685,11 +4685,11 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
double rdata_end = PIL_check_seconds_timer();
#endif
- TaskScheduler *task_scheduler;
TaskPool *task_pool;
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create_suspended(task_scheduler, NULL, TASK_PRIORITY_HIGH);
+ /* Create a suspended pool as the finalize method could be called too early.
+ * See `extract_run`. */
+ task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH);
size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t);
int32_t *task_counters = MEM_callocN(counters_size, __func__);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 28c8570e897..e3c364eef6d 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1068,7 +1068,7 @@ static void drw_engines_draw_text(void)
}
/* Draw render engine info. */
-void DRW_draw_region_engine_info(int xoffset, int yoffset)
+void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height)
{
LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) {
DrawEngineType *engine = link->data;
@@ -1091,8 +1091,8 @@ void DRW_draw_region_engine_info(int xoffset, int yoffset)
if (*chr_current == '\n') {
char info[GPU_INFO_SIZE];
BLI_strncpy(info, chr_start, line_len + 1);
- yoffset -= U.widget_unit;
- BLF_draw_default(xoffset, yoffset, 0.0f, info, sizeof(info));
+ *yoffset -= line_height;
+ BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info));
/* Re-start counting. */
chr_start = chr_current + 1;
@@ -1102,8 +1102,8 @@ void DRW_draw_region_engine_info(int xoffset, int yoffset)
char info[GPU_INFO_SIZE];
BLI_strncpy(info, chr_start, line_len + 1);
- yoffset -= U.widget_unit;
- BLF_draw_default(xoffset, yoffset, 0.0f, info, sizeof(info));
+ *yoffset -= line_height;
+ BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info));
BLF_disable(font_id, BLF_SHADOW);
}
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index b451cfb1d05..7eac082a9e1 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -99,6 +99,10 @@ static void drw_deferred_shader_compilation_exec(void *custom_data,
DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data;
void *gl_context = comp->gl_context;
+#if TRUST_NO_ONE
+ BLI_assert(gl_context != NULL);
+#endif
+
WM_opengl_context_activate(gl_context);
while (true) {
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index d48e09e0504..cd17a490240 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -51,6 +51,7 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
#include "DNA_volume_types.h"
@@ -3033,6 +3034,83 @@ static bAnimChannelType ACF_DSVOLUME = {
acf_dsvolume_setting_ptr /* pointer for setting */
};
+/* Simulation Expander ----------------------------------------- */
+
+static int acf_dssimulation_icon(bAnimListElem *UNUSED(ale))
+{
+ /* TODO: Use correct icon. */
+ return ICON_PHYSICS;
+}
+
+static int acf_dssimulation_setting_flag(bAnimContext *UNUSED(ac),
+ eAnimChannel_Settings setting,
+ bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return SIM_DS_EXPAND;
+
+ case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
+ return ADT_NLA_EVAL_OFF;
+
+ case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
+ *neg = true;
+ return ADT_CURVES_NOT_VISIBLE;
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
+ default: /* unsupported */
+ return 0;
+ }
+}
+
+static void *acf_dssimulation_setting_ptr(bAnimListElem *ale,
+ eAnimChannel_Settings setting,
+ short *type)
+{
+ Simulation *simulation = (Simulation *)ale->data;
+
+ /* clear extra return data first */
+ *type = 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return GET_ACF_FLAG_PTR(simulation->flag, type);
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
+ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ if (simulation->adt)
+ return GET_ACF_FLAG_PTR(simulation->adt->flag, type);
+ return NULL;
+
+ default: /* unsupported */
+ return NULL;
+ }
+}
+
+static bAnimChannelType ACF_DSSIMULATION = {
+ "Simulation Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_generic_dataexpand_color, /* backdrop color */
+ acf_generic_dataexpand_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_basic_offset, /* offset */
+
+ acf_generic_idblock_name, /* name */
+ acf_generic_idblock_name_prop, /* name prop */
+ acf_dssimulation_icon, /* icon */
+
+ acf_generic_dataexpand_setting_valid, /* has setting */
+ acf_dssimulation_setting_flag, /* flag for setting */
+ acf_dssimulation_setting_ptr /* pointer for setting */
+};
+
/* GPencil Expander ------------------------------------------- */
// TODO: just get this from RNA?
@@ -4049,6 +4127,7 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_DSHAIR; /* Hair Channel */
animchannelTypeInfo[type++] = &ACF_DSPOINTCLOUD; /* PointCloud Channel */
animchannelTypeInfo[type++] = &ACF_DSVOLUME; /* Volume Channel */
+ animchannelTypeInfo[type++] = &ACF_DSSIMULATION; /* Simulation Channel */
animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 4e3dc3cb220..a7ca84eb6c6 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -138,7 +138,8 @@ void ANIM_set_active_channel(bAnimContext *ac,
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale->adt) {
ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE);
@@ -194,7 +195,8 @@ void ANIM_set_active_channel(bAnimContext *ac,
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale && ale->adt) {
ale->adt->flag |= ADT_UI_ACTIVE;
@@ -332,7 +334,8 @@ void ANIM_deselect_anim_channels(
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) {
sel = ACHANNEL_SETFLAG_CLEAR;
}
@@ -428,7 +431,8 @@ void ANIM_deselect_anim_channels(
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale->adt) {
ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
@@ -2965,7 +2969,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* sanity checking... */
if (ale->adt) {
/* select/deselect */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 4dc0bef3a1b..4c7c3a2c253 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -67,6 +67,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
#include "DNA_userdef_types.h"
@@ -86,6 +87,7 @@
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_layer.h"
@@ -826,6 +828,18 @@ static bAnimListElem *make_new_animlistelem(void *data,
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_DSSIMULATION: {
+ Simulation *simulation = (Simulation *)data;
+ AnimData *adt = simulation->adt;
+
+ ale->flag = FILTER_SIMULATION_OBJD(simulation);
+
+ ale->key_data = (adt) ? adt->action : NULL;
+ ale->datatype = ALE_ACT;
+
+ ale->adt = BKE_animdata_from_id(data);
+ break;
+ }
case ANIMTYPE_DSSKEY: {
Key *key = (Key *)data;
AnimData *adt = key->adt;
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 3ae4e3bf998..82e24eaa6e3 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -40,6 +40,7 @@
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index e22fddc6d67..2dae4e8b4c5 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -633,7 +633,7 @@ bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const
BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy);
if (BLI_lasso_is_point_inside(
- data_lasso->mcords, data_lasso->mcords_tot, xy_view[0], xy_view[1], INT_MAX)) {
+ data_lasso->mcoords, data_lasso->mcoords_len, xy_view[0], xy_view[1], INT_MAX)) {
return true;
}
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 49e936d22aa..04061ceea51 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -50,6 +50,7 @@
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index bc854747a68..5f3b876efaf 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -42,7 +42,7 @@
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index ae08aee3c47..481282d6df3 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -544,71 +544,56 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
/* only if all channels exist, proceed */
if (fcu_w && fcu_x && fcu_y && fcu_z) {
- float quat_prev[4], quat_prev_orig[4];
- float quat_next[4], quat_next_orig[4];
- float quat_curr[4], quat_curr_orig[4];
float quat_final[4];
- copy_qt_qt(quat_curr_orig, pchan->quat);
-
- /* get 2 quats */
- quat_prev_orig[0] = evaluate_fcurve(fcu_w, prevFrameF);
- quat_prev_orig[1] = evaluate_fcurve(fcu_x, prevFrameF);
- quat_prev_orig[2] = evaluate_fcurve(fcu_y, prevFrameF);
- quat_prev_orig[3] = evaluate_fcurve(fcu_z, prevFrameF);
-
- quat_next_orig[0] = evaluate_fcurve(fcu_w, nextFrameF);
- quat_next_orig[1] = evaluate_fcurve(fcu_x, nextFrameF);
- quat_next_orig[2] = evaluate_fcurve(fcu_y, nextFrameF);
- quat_next_orig[3] = evaluate_fcurve(fcu_z, nextFrameF);
-
- normalize_qt_qt(quat_prev, quat_prev_orig);
- normalize_qt_qt(quat_next, quat_next_orig);
- normalize_qt_qt(quat_curr, quat_curr_orig);
-
/* perform blending */
if (pso->mode == POSESLIDE_BREAKDOWN) {
/* Just perform the interpolation between quat_prev and
* quat_next using pso->percentage as a guide. */
- interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
- }
- else if (pso->mode == POSESLIDE_PUSH) {
- float quat_diff[4];
+ float quat_prev[4];
+ float quat_next[4];
+
+ quat_prev[0] = evaluate_fcurve(fcu_w, prevFrameF);
+ quat_prev[1] = evaluate_fcurve(fcu_x, prevFrameF);
+ quat_prev[2] = evaluate_fcurve(fcu_y, prevFrameF);
+ quat_prev[3] = evaluate_fcurve(fcu_z, prevFrameF);
- /* calculate the delta transform from the previous to the current */
- /* TODO: investigate ways to favor one transform more? */
- sub_qt_qtqt(quat_diff, quat_curr, quat_prev);
+ quat_next[0] = evaluate_fcurve(fcu_w, nextFrameF);
+ quat_next[1] = evaluate_fcurve(fcu_x, nextFrameF);
+ quat_next[2] = evaluate_fcurve(fcu_y, nextFrameF);
+ quat_next[3] = evaluate_fcurve(fcu_z, nextFrameF);
- /* increase the original by the delta transform, by an amount determined by percentage */
- add_qt_qtqt(quat_final, quat_curr, quat_diff, pso->percentage);
+ normalize_qt(quat_prev);
+ normalize_qt(quat_next);
- normalize_qt(quat_final);
+ interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
}
else {
- BLI_assert(pso->mode == POSESLIDE_RELAX);
- float quat_interp[4], quat_final_prev[4];
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
+ /* POSESLIDE_PUSH and POSESLIDE_RELAX. */
+ float quat_breakdown[4];
+ float quat_curr[4];
- copy_qt_qt(quat_final, quat_curr);
+ copy_qt_qt(quat_curr, pchan->quat);
- /* perform this blending several times until a satisfactory result is reached */
- while (iters-- > 0) {
- /* calculate the interpolation between the endpoints */
- interp_qt_qtqt(quat_interp,
- quat_prev,
- quat_next,
- (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame));
+ quat_breakdown[0] = evaluate_fcurve(fcu_w, cframe);
+ quat_breakdown[1] = evaluate_fcurve(fcu_x, cframe);
+ quat_breakdown[2] = evaluate_fcurve(fcu_y, cframe);
+ quat_breakdown[3] = evaluate_fcurve(fcu_z, cframe);
- normalize_qt_qt(quat_final_prev, quat_final);
+ normalize_qt(quat_breakdown);
+ normalize_qt(quat_curr);
- /* tricky interpolations - blending between original and new */
- interp_qt_qtqt(quat_final, quat_final_prev, quat_interp, 1.0f / 6.0f);
+ if (pso->mode == POSESLIDE_PUSH) {
+ interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + pso->percentage);
+ }
+ else {
+ BLI_assert(pso->mode == POSESLIDE_RELAX);
+ interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, pso->percentage);
}
}
/* Apply final to the pose bone, keeping compatible for similar keyframe positions. */
- quat_to_compatible_quat(pchan->quat, quat_final, quat_curr_orig);
+ quat_to_compatible_quat(pchan->quat, quat_final, pchan->quat);
}
/* free the path now */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 31c89ca9f43..1d2bf152777 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -1240,7 +1240,7 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
workob.adt = ob->adt;
workob.pose = dummyPose;
- BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(&workob.id, workob.adt, cframe, ADT_RECALC_ANIM, false);
/* copy back values, but on selected bones only */
for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index adaf4ab2459..86423d907b5 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -524,131 +524,6 @@ static void annotation_draw_strokes(const bGPDframe *gpf,
GPU_program_point_size(false);
}
-/* Draw selected verts for strokes being edited */
-static void annotation_draw_strokes_edit(bGPDlayer *gpl,
- const bGPDframe *gpf,
- int offsx,
- int offsy,
- int winx,
- int winy,
- short dflag,
- float alpha)
-{
- /* if alpha 0 do not draw */
- if (alpha == 0.0f) {
- return;
- }
-
- const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
- int mask_orig = 0;
-
- /* set up depth masks... */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- if (no_xray) {
- glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
- glDepthMask(0);
- GPU_depth_test(true);
-
- /* first arg is normally rv3d->dist, but this isn't
- * available here and seems to work quite well without */
- bglPolygonOffset(1.0f, 1.0f);
- }
- }
-
- GPU_program_point_size(true);
-
- /* draw stroke verts */
- LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- /* check if stroke can be drawn */
- if (annotation_can_draw_stroke(gps, dflag) == false) {
- continue;
- }
-
- /* Optimization: only draw points for selected strokes
- * We assume that selected points can only occur in
- * strokes that are selected too.
- */
- if ((gps->flag & GP_STROKE_SELECT) == 0) {
- continue;
- }
-
- /* Get size of verts:
- * - The selected state needs to be larger than the unselected state so that
- * they stand out more.
- * - We use the theme setting for size of the unselected verts
- */
- float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
- float vsize;
- if ((int)bsize > 8) {
- vsize = 10.0f;
- bsize = 8.0f;
- }
- else {
- vsize = bsize + 2;
- }
-
- /* Why? */
- UNUSED_VARS(vsize);
-
- float selectColor[4];
- UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
- selectColor[3] = alpha;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos; /* specified later */
- uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
- }
- else {
- pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR);
- }
-
- immBegin(GPU_PRIM_POINTS, gps->totpoints);
-
- /* Draw all the stroke points (selected or not) */
- bGPDspoint *pt = gps->points;
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* size and color first */
- immAttr3fv(color, gpl->color);
- immAttr1f(size, bsize);
-
- /* then position */
- if (gps->flag & GP_STROKE_3DSPACE) {
- immVertex3fv(pos, &pt->x);
- }
- else {
- float co[2];
- annotation_calc_2d_stroke_fxy(&pt->x, gps->flag, offsx, offsy, winx, winy, co);
- immVertex2fv(pos, co);
- }
- }
-
- immEnd();
- immUnbindProgram();
- }
-
- GPU_program_point_size(false);
-
- /* clear depth mask */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- if (no_xray) {
- glDepthMask(mask_orig);
- GPU_depth_test(false);
-
- bglPolygonOffset(0.0, 0.0);
-#if 0
- glDisable(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(0, 0);
-#endif
- }
- }
-}
-
/* ----- General Drawing ------ */
/* draw onion-skinning for a layer */
static void annotation_draw_onionskins(
@@ -724,7 +599,7 @@ static void annotation_draw_onionskins(
/* loop over gpencil data layers, drawing them */
static void annotation_draw_data_layers(
- bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha)
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
float ink[4];
@@ -767,21 +642,6 @@ static void annotation_draw_data_layers(
/* draw the strokes already in active frame */
annotation_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, lthick, ink);
- /* Draw verts of selected strokes:
- * - when doing OpenGL renders, we don't want to be showing these, as that ends up
- * flickering
- * - locked layers can't be edited, so there's no point showing these verts
- * as they will have no bearings on what gets edited
- * - only show when in editmode, since operators shouldn't work otherwise
- * (NOTE: doing it this way means that the toggling editmode
- * shows visible change immediately).
- */
- /* XXX: perhaps we don't want to show these when users are drawing... */
- if ((G.f & G_FLAG_RENDER_VIEWPORT) == 0 && (gpl->flag & GP_LAYER_LOCKED) == 0 &&
- (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
- annotation_draw_strokes_edit(gpl, gpf, offsx, offsy, winx, winy, dflag, alpha);
- }
-
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
* that is being edited. (Stroke buffer is currently stored in gp-data)
*/
@@ -803,57 +663,9 @@ static void annotation_draw_data_layers(
}
}
-/* draw a short status message in the top-right corner */
-static void annotation_draw_status_text(const bGPdata *gpd, ARegion *region)
-{
-
- /* Cannot draw any status text when drawing OpenGL Renders */
- if (G.f & G_FLAG_RENDER_VIEWPORT) {
- return;
- }
-
- /* Get bounds of region - Necessary to avoid problems with region overlap */
- const rcti *rect = ED_region_visible_rect(region);
-
- /* for now, this should only be used to indicate when we are in stroke editmode */
- if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- const char *printable = IFACE_("GPencil Stroke Editing");
- float printable_size[2];
-
- int font_id = BLF_default();
-
- BLF_width_and_height(
- font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
-
- int xco = (rect->xmax - U.widget_unit) - (int)printable_size[0];
- int yco = (rect->ymax - U.widget_unit);
-
- /* text label */
- UI_FontThemeColor(font_id, TH_TEXT_HI);
-#ifdef WITH_INTERNATIONAL
- BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
-#else
- BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
-#endif
-
- /* grease pencil icon... */
- // XXX: is this too intrusive?
- GPU_blend_set_func_separate(
- GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- GPU_blend(true);
-
- xco -= U.widget_unit;
- yco -= (int)printable_size[1] / 2;
-
- UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
-
- GPU_blend(false);
- }
-}
-
/* draw grease-pencil datablock */
static void annotation_draw_data(
- bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha)
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
/* turn on smooth lines (i.e. anti-aliasing) */
GPU_line_smooth(true);
@@ -864,7 +676,7 @@ static void annotation_draw_data(
GPU_blend(true);
/* draw! */
- annotation_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ annotation_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag);
/* turn off alpha blending, then smooth lines */
GPU_blend(false); // alpha blending
@@ -884,7 +696,6 @@ static void annotation_draw_data_all(Scene *scene,
const char spacetype)
{
bGPdata *gpd_source = NULL;
- float alpha = 1.0f;
if (scene) {
if (spacetype == SPACE_VIEW3D) {
@@ -897,14 +708,14 @@ static void annotation_draw_data_all(Scene *scene,
}
if (gpd_source) {
- annotation_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ annotation_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag);
}
}
/* scene/clip data has already been drawn, only object/track data is drawn here
* if gpd_source == gpd, we don't have any object/track data and we can skip */
if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
- annotation_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ annotation_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag);
}
}
@@ -1026,11 +837,6 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
annotation_draw_data_all(
scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype);
-
- /* draw status text (if in screen/pixel-space) */
- if (!onlyv2d) {
- annotation_draw_status_text(gpd, region);
- }
}
/* draw annotations sketches to specified 3d-view assuming that matrices are already set
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index c05162510d7..86b08880d57 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -55,7 +55,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_lib_id.h"
@@ -3193,7 +3193,7 @@ void GPENCIL_OT_material_unlock_all(wmOperatorType *ot)
/* ***************** Select all strokes using color ************************ */
-static int gpencil_select_material_exec(bContext *C, wmOperator *op)
+static int gpencil_material_select_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
@@ -3263,15 +3263,15 @@ static int gpencil_select_material_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_select_material(wmOperatorType *ot)
+void GPENCIL_OT_material_select(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Material";
- ot->idname = "GPENCIL_OT_select_material";
+ ot->idname = "GPENCIL_OT_material_select";
ot->description = "Select/Deselect all Grease Pencil strokes using current material";
/* callbacks */
- ot->exec = gpencil_select_material_exec;
+ ot->exec = gpencil_material_select_exec;
ot->poll = gpencil_active_material_poll;
/* flags */
@@ -3282,6 +3282,48 @@ void GPENCIL_OT_select_material(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/* ***************** Set active material ************************* */
+static int gpencil_material_set_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ int slot = RNA_enum_get(op->ptr, "slot");
+
+ /* Try to get material */
+ if ((slot < 1) || (slot > ob->totcol)) {
+ BKE_reportf(
+ op->reports, RPT_ERROR, "Cannot change to non-existent material (index = %d)", slot);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Set active material. */
+ ob->actcol = slot;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_material_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Material";
+ ot->idname = "GPENCIL_OT_material_set";
+ ot->description = "Set active material";
+
+ /* callbacks */
+ ot->exec = gpencil_material_set_exec;
+ ot->poll = gpencil_active_material_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Material to use (dynamic enum) */
+ ot->prop = RNA_def_enum(ot->srna, "slot", DummyRNA_DEFAULT_items, 0, "Material Slot", "");
+ RNA_def_enum_funcs(ot->prop, ED_gpencil_material_enum_itemf);
+}
+
/* ***************** Set selected stroke material the active material ************************ */
static int gpencil_set_active_material_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 77e45642939..4a4ade4e98f 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -4547,8 +4547,8 @@ void GPENCIL_OT_stroke_smooth(wmOperatorType *ot)
/* smart stroke cutter for trimming stroke ends */
struct GP_SelectLassoUserData {
rcti rect;
- const int (*mcords)[2];
- int mcords_len;
+ const int (*mcoords)[2];
+ int mcoords_len;
};
static bool gpencil_test_lasso(bGPDstroke *gps,
@@ -4564,7 +4564,7 @@ static bool gpencil_test_lasso(bGPDstroke *gps,
gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
/* test if in lasso */
return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) &&
- BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
+ BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX));
}
typedef bool (*GPencilTestFn)(bGPDstroke *gps,
@@ -4742,19 +4742,19 @@ static int gpencil_cutter_exec(bContext *C, wmOperator *op)
}
struct GP_SelectLassoUserData data = {0};
- data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
+ data.mcoords = WM_gesture_lasso_path_to_array(C, op, &data.mcoords_len);
/* Sanity check. */
- if (data.mcords == NULL) {
+ if (data.mcoords == NULL) {
return OPERATOR_PASS_THROUGH;
}
/* Compute boundbox of lasso (for faster testing later). */
- BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
+ BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len);
gpencil_cutter_lasso_select(C, op, gpencil_test_lasso, &data);
- MEM_freeN((void *)data.mcords);
+ MEM_freeN((void *)data.mcoords);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index c5e5a0b79ef..19b53d0662d 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -345,6 +345,10 @@ const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bCon
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
+const struct EnumPropertyItem *ED_gpencil_material_enum_itemf(struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ bool *r_free);
/* ***************************************************** */
/* Operator Defines */
@@ -550,7 +554,8 @@ void GPENCIL_OT_material_reveal(struct wmOperatorType *ot);
void GPENCIL_OT_material_lock_all(struct wmOperatorType *ot);
void GPENCIL_OT_material_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_material_lock_unused(struct wmOperatorType *ot);
-void GPENCIL_OT_select_material(struct wmOperatorType *ot);
+void GPENCIL_OT_material_select(struct wmOperatorType *ot);
+void GPENCIL_OT_material_set(struct wmOperatorType *ot);
void GPENCIL_OT_set_active_material(struct wmOperatorType *ot);
/* convert old 2.7 files to 2.8 */
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 0171a81f5eb..94c86572fd3 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -653,7 +653,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_material_reveal);
WM_operatortype_append(GPENCIL_OT_material_lock_all);
WM_operatortype_append(GPENCIL_OT_material_unlock_all);
- WM_operatortype_append(GPENCIL_OT_select_material);
+ WM_operatortype_append(GPENCIL_OT_material_select);
+ WM_operatortype_append(GPENCIL_OT_material_set);
/* Editing (Time) --------------- */
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index e25576f32aa..69d22b52ded 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -1327,8 +1327,8 @@ void GPENCIL_OT_select_box(wmOperatorType *ot)
struct GP_SelectLassoUserData {
rcti rect;
- const int (*mcords)[2];
- int mcords_len;
+ const int (*mcoords)[2];
+ int mcoords_len;
};
static bool gpencil_test_lasso(bGPDstroke *gps,
@@ -1344,25 +1344,25 @@ static bool gpencil_test_lasso(bGPDstroke *gps,
gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
/* test if in lasso boundbox + within the lasso noose */
return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) &&
- BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
+ BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX));
}
static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
{
struct GP_SelectLassoUserData data = {0};
- data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
+ data.mcoords = WM_gesture_lasso_path_to_array(C, op, &data.mcoords_len);
/* Sanity check. */
- if (data.mcords == NULL) {
+ if (data.mcoords == NULL) {
return OPERATOR_PASS_THROUGH;
}
/* Compute boundbox of lasso (for faster testing later). */
- BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
+ BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len);
int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, &data);
- MEM_freeN((void *)data.mcords);
+ MEM_freeN((void *)data.mcoords);
return ret;
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 3d571773bc8..6a7bb2012a7 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -481,6 +481,40 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
return item;
}
+/* Just existing Materials */
+const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ Object *ob = CTX_data_active_object(C);
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, ob)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* Existing materials */
+ for (i = 1; i <= ob->totcol; i++) {
+ Material *ma = BKE_object_material_get(ob, i);
+ if (ma) {
+ item_tmp.identifier = ma->id.name + 2;
+ item_tmp.name = ma->id.name + 2;
+ item_tmp.value = i;
+ item_tmp.icon = ma->preview->icon_id;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
/* ******************************************************** */
/* Brush Tool Core */
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index a9b34e3c735..7d38792f332 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -229,6 +229,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSHAIR,
ANIMTYPE_DSPOINTCLOUD,
ANIMTYPE_DSVOLUME,
+ ANIMTYPE_DSSIMULATION,
ANIMTYPE_SHAPEKEY,
@@ -356,6 +357,8 @@ typedef enum eAnimFilter_Flags {
#define FILTER_HAIR_OBJD(ha) (CHECK_TYPE_INLINE(ha, Hair *), ((ha->flag & HA_DS_EXPAND)))
#define FILTER_POINTS_OBJD(pt) (CHECK_TYPE_INLINE(pt, PointCloud *), ((pt->flag & PT_DS_EXPAND)))
#define FILTER_VOLUME_OBJD(vo) (CHECK_TYPE_INLINE(vo, Volume *), ((vo->flag & VO_DS_EXPAND)))
+#define FILTER_SIMULATION_OBJD(sim) \
+ (CHECK_TYPE_INLINE(sim, Simulation *), ((sim->flag & SIM_DS_EXPAND)))
/* Variable use expanders */
#define FILTER_NTREE_DATA(ntree) \
(CHECK_TYPE_INLINE(ntree, bNodeTree *), (((ntree)->flag & NTREE_DS_EXPAND)))
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 910cf362a37..a8476e3d1ca 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -69,7 +69,7 @@ void ED_space_image_get_size(struct SpaceImage *sima, int *r_width, int *r_heigh
void ED_space_image_get_size_fl(struct SpaceImage *sima, float r_size[2]);
void ED_space_image_get_aspect(struct SpaceImage *sima, float *r_aspx, float *r_aspy);
void ED_space_image_get_zoom(struct SpaceImage *sima,
- struct ARegion *region,
+ const struct ARegion *region,
float *r_zoomx,
float *r_zoomy);
void ED_space_image_get_uv_aspect(struct SpaceImage *sima, float *r_aspx, float *r_aspy);
@@ -88,14 +88,18 @@ void ED_image_get_uv_aspect(struct Image *ima,
float *r_aspx,
float *r_aspy);
void ED_image_mouse_pos(struct SpaceImage *sima,
- struct ARegion *region,
+ const struct ARegion *region,
const int mval[2],
float co[2]);
void ED_image_view_center_to_point(struct SpaceImage *sima, float x, float y);
-void ED_image_point_pos(
- struct SpaceImage *sima, struct ARegion *region, float x, float y, float *r_x, float *r_y);
+void ED_image_point_pos(struct SpaceImage *sima,
+ const struct ARegion *region,
+ float x,
+ float y,
+ float *r_x,
+ float *r_y);
void ED_image_point_pos__reverse(struct SpaceImage *sima,
- struct ARegion *region,
+ const struct ARegion *region,
const float co[2],
float r_co[2]);
bool ED_image_slot_cycle(struct Image *image, int direction);
diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h
index 82662a6b118..1146c49bef2 100644
--- a/source/blender/editors/include/ED_info.h
+++ b/source/blender/editors/include/ED_info.h
@@ -31,9 +31,9 @@ struct Main;
/* info_stats.c */
void ED_info_stats_clear(struct ViewLayer *view_layer);
-const char *ED_info_stats_string(struct Main *bmain,
- struct Scene *scene,
- struct ViewLayer *view_layer);
+const char *ED_info_footer_string(struct ViewLayer *view_layer);
+void ED_info_draw_stats(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index 3ae0c254000..3ae864721e8 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -106,8 +106,8 @@ typedef enum eEditKeyframes_Mirror {
typedef struct KeyframeEdit_LassoData {
rctf *rectf_scaled;
const rctf *rectf_view;
- const int (*mcords)[2];
- int mcords_tot;
+ const int (*mcoords)[2];
+ int mcoords_len;
} KeyframeEdit_LassoData;
/* use with BEZT_OK_REGION_CIRCLE */
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 7a1f64b61d4..1dc98cfee2f 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -37,6 +37,7 @@ struct Tex;
struct View2D;
struct bContext;
struct bNode;
+struct bNodeSocket;
struct bNodeSocketType;
struct bNodeTree;
struct bNodeTree;
@@ -79,6 +80,10 @@ void ED_node_draw_snap(
struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos);
/* node_draw.c */
+void ED_node_socket_draw(struct bNodeSocket *sock,
+ const struct rcti *rect,
+ const float color[4],
+ float scale);
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
@@ -94,6 +99,7 @@ void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typein
bool ED_node_is_compositor(struct SpaceNode *snode);
bool ED_node_is_shader(struct SpaceNode *snode);
bool ED_node_is_texture(struct SpaceNode *snode);
+bool ED_node_is_simulation(struct SpaceNode *snode);
void ED_node_shader_default(const struct bContext *C, struct ID *id);
void ED_node_composit_default(const struct bContext *C, struct Scene *scene);
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index beed0f98fb5..d3fc5174dd9 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -27,9 +27,9 @@
extern "C" {
#endif
+struct Base;
struct ListBase;
struct bContext;
-struct Base;
bool ED_outliner_collections_editor_poll(struct bContext *C);
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index c8a4dc5b49d..6959cac7efe 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -71,7 +71,7 @@ bool PE_mouse_particles(
bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op);
bool PE_circle_select(struct bContext *C, const int sel_op, const int mval[2], float rad);
int PE_lasso_select(struct bContext *C,
- const int mcords[][2],
+ const int mcoords[][2],
const short moves,
const int sel_op);
bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index beba4a7199b..27b7511c8a2 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -157,6 +157,8 @@ int BIF_countTransformOrientation(const struct bContext *C);
#define P_GPENCIL_EDIT (1 << 13)
#define P_CURSOR_EDIT (1 << 14)
#define P_CLNOR_INVALIDATE (1 << 15)
+/* For properties performed when confirming the transformation. */
+#define P_POST_TRANSFORM (1 << 16)
void Transform_Properties(struct wmOperatorType *ot, int flags);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 774cf8c509f..f4dd2da06fc 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -250,6 +250,8 @@ enum {
UI_BUT_TEXT_RIGHT = 1 << 3,
/** Prevent the button to show any tooltip. */
UI_BUT_NO_TOOLTIP = 1 << 4,
+ /** Do not add the usual horizontal padding for text drawing. */
+ UI_BUT_NO_TEXT_PADDING = 1 << 5,
/* Button align flag, for drawing groups together.
* Used in 'uiBlock.flag', take care! */
@@ -1585,6 +1587,8 @@ int UI_searchbox_size_x(void);
/* check if a string is in an existing search box */
int UI_search_items_find_index(uiSearchItems *items, const char *name);
+void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
+
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg);
void UI_block_func_butmenu_set(uiBlock *block, uiMenuHandleFunc func, void *arg);
void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2);
@@ -1668,6 +1672,7 @@ void UI_panel_end(const struct ScrArea *area,
void UI_panels_scale(struct ARegion *region, float new_width);
void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y);
int UI_panel_size_y(const struct Panel *panel);
+bool UI_panel_is_dragging(const struct Panel *panel);
bool UI_panel_category_is_visible(const struct ARegion *region);
void UI_panel_category_add(struct ARegion *region, const char *name);
@@ -1772,6 +1777,10 @@ enum {
UI_ITEM_O_DEPRESS = 1 << 10,
UI_ITEM_R_COMPACT = 1 << 11,
UI_ITEM_R_CHECKBOX_INVERT = 1 << 12,
+ /** Don't add a real decorator item, just blank space. */
+ UI_ITEM_R_FORCE_BLANK_DECORATE = 1 << 13,
+ /* Even create the property split layout if there's no name to show there. */
+ UI_ITEM_R_SPLIT_EMPTY_NAME = 1 << 14,
};
#define UI_HEADER_OFFSET ((void)0, 0.4f * UI_UNIT_X)
@@ -1782,6 +1791,9 @@ enum {
UI_TEMPLATE_OP_PROPS_SHOW_EMPTY = 1 << 1,
UI_TEMPLATE_OP_PROPS_COMPACT = 1 << 2,
UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED = 1 << 3,
+ /* Disable property split for the default layout (custom ui callbacks still have full control
+ * over the layout and can enable it). */
+ UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT = 1 << 4,
};
/* used for transp checkers */
@@ -1869,7 +1881,9 @@ bool uiLayoutGetPropDecorate(uiLayout *layout);
/* layout specifiers */
uiLayout *uiLayoutRow(uiLayout *layout, bool align);
+uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumn(uiLayout *layout, bool align);
+uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align);
uiLayout *uiLayoutGridFlow(uiLayout *layout,
bool row_major,
@@ -2044,11 +2058,11 @@ void uiTemplateOperatorSearch(uiLayout *layout);
void UI_but_func_menu_search(uiBut *but);
void uiTemplateMenuSearch(uiLayout *layout);
-eAutoPropButsReturn uiTemplateOperatorPropertyButs(const struct bContext *C,
- uiLayout *layout,
- struct wmOperator *op,
- const eButLabelAlign label_align,
- const short flag);
+void uiTemplateOperatorPropertyButs(const struct bContext *C,
+ uiLayout *layout,
+ struct wmOperator *op,
+ eButLabelAlign label_align,
+ short flag);
void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C);
void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
@@ -2088,6 +2102,7 @@ void uiTemplateList(uiLayout *layout,
bool sort_reverse,
bool sort_lock);
void uiTemplateNodeLink(uiLayout *layout,
+ struct bContext *C,
struct bNodeTree *ntree,
struct bNode *node,
struct bNodeSocket *input);
@@ -2297,6 +2312,14 @@ void uiItemsFullEnumO_items(uiLayout *layout,
const EnumPropertyItem *item_array,
int totitem);
+typedef struct uiPropertySplitWrapper {
+ uiLayout *label_column;
+ uiLayout *property_row;
+ uiLayout *decorate_column;
+} uiPropertySplitWrapper;
+
+uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
+
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
void uiItemL_ex(
uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert);
@@ -2308,6 +2331,9 @@ void uiItemM_ptr(uiLayout *layout, struct MenuType *mt, const char *name, int ic
void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon);
/* menu contents */
void uiItemMContents(uiLayout *layout, const char *menuname);
+/* Decorators */
+void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index);
+void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index);
/* value */
void uiItemV(uiLayout *layout, const char *name, int icon, int argval);
/* separator */
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index d4db1b14074..ffc06e94a90 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -137,9 +137,9 @@ void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, con
void UI_view2d_view_restore(const struct bContext *C);
/* grid drawing */
-void UI_view2d_constant_grid_draw(struct View2D *v2d, float step);
+void UI_view2d_constant_grid_draw(const struct View2D *v2d, float step);
void UI_view2d_multi_grid_draw(
- struct View2D *v2d, int colorid, float step, int level_size, int totlevels);
+ const struct View2D *v2d, int colorid, float step, int level_size, int totlevels);
void UI_view2d_draw_lines_y__values(const struct View2D *v2d);
void UI_view2d_draw_lines_x__values(const struct View2D *v2d);
@@ -209,14 +209,17 @@ bool UI_view2d_view_to_region_clip(
const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
void UI_view2d_view_to_region(
- struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
-void UI_view2d_view_to_region_fl(
- struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL();
-void UI_view2d_view_to_region_m4(struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL();
-void UI_view2d_view_to_region_rcti(struct View2D *v2d,
+ const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
+void UI_view2d_view_to_region_fl(const struct View2D *v2d,
+ float x,
+ float y,
+ float *r_region_x,
+ float *r_region_y) ATTR_NONNULL();
+void UI_view2d_view_to_region_m4(const struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL();
+void UI_view2d_view_to_region_rcti(const struct View2D *v2d,
const struct rctf *rect_src,
struct rcti *rect_dst) ATTR_NONNULL();
-bool UI_view2d_view_to_region_rcti_clip(struct View2D *v2d,
+bool UI_view2d_view_to_region_rcti_clip(const struct View2D *v2d,
const struct rctf *rect_src,
struct rcti *rect_dst) ATTR_NONNULL();
@@ -228,9 +231,9 @@ void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_
void UI_view2d_scale_get(struct View2D *v2d, float *r_x, float *r_y);
float UI_view2d_scale_get_x(const struct View2D *v2d);
float UI_view2d_scale_get_y(const struct View2D *v2d);
-void UI_view2d_scale_get_inverse(struct View2D *v2d, float *r_x, float *r_y);
+void UI_view2d_scale_get_inverse(const struct View2D *v2d, float *r_x, float *r_y);
-void UI_view2d_center_get(struct View2D *v2d, float *r_x, float *r_y);
+void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y);
void UI_view2d_center_set(struct View2D *v2d, float x, float y);
void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 9ec660a9714..8ff3dc11dc7 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -641,6 +641,26 @@ static int ui_but_calc_float_precision(uiBut *but, double value)
/* ************** BLOCK ENDING FUNCTION ************* */
+bool ui_but_rna_equals(const uiBut *a, const uiBut *b)
+{
+ return ui_but_rna_equals_ex(a, &b->rnapoin, b->rnaprop, b->rnaindex);
+}
+
+bool ui_but_rna_equals_ex(const uiBut *but,
+ const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ int index)
+{
+ if (but->rnapoin.data != ptr->data) {
+ return false;
+ }
+ if (but->rnaprop != prop || but->rnaindex != index) {
+ return false;
+ }
+
+ return true;
+}
+
/* NOTE: if but->poin is allocated memory for every defbut, things fail... */
static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
{
@@ -649,10 +669,7 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
if (but->retval != oldbut->retval) {
return false;
}
- if (but->rnapoin.data != oldbut->rnapoin.data) {
- return false;
- }
- if (but->rnaprop != oldbut->rnaprop || but->rnaindex != oldbut->rnaindex) {
+ if (!ui_but_rna_equals(but, oldbut)) {
return false;
}
if (but->func != oldbut->func) {
@@ -979,7 +996,9 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
UI_BTYPE_BUT_MENU,
UI_BTYPE_MENU,
UI_BTYPE_BLOCK,
- UI_BTYPE_PULLDOWN) ||
+ UI_BTYPE_PULLDOWN,
+ /* For PIE-menus. */
+ UI_BTYPE_ROW) ||
(but->flag & UI_HIDDEN)) {
/* pass */
}
@@ -6486,6 +6505,13 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
return but;
}
+void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
+{
+ but->flag |= UI_BUT_NODE_LINK;
+ but->custom_data = socket;
+ rgba_float_to_uchar(but->col, draw_color);
+}
+
/**
* push a new event onto event queue to activate the given button
* (usually a text-field) upon entering a popup
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 15fc23bc539..8c9768f523d 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -28,12 +28,14 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_nla.h"
@@ -114,10 +116,40 @@ void ui_but_anim_flag(uiBut *but, float cfra)
}
}
+static uiBut *ui_but_anim_decorate_find_attached_button(uiBut *but_decorate)
+{
+ uiBut *but_iter = NULL;
+
+ BLI_assert(UI_but_is_decorator(but_decorate));
+ BLI_assert(but_decorate->rnasearchpoin.data && but_decorate->rnasearchprop);
+
+ LISTBASE_CIRCULAR_BACKWARD_BEGIN (&but_decorate->block->buttons, but_iter, but_decorate->prev) {
+ if (but_iter != but_decorate &&
+ ui_but_rna_equals_ex(but_iter,
+ &but_decorate->rnasearchpoin,
+ but_decorate->rnasearchprop,
+ POINTER_AS_INT(but_decorate->custom_data))) {
+ return but_iter;
+ }
+ }
+ LISTBASE_CIRCULAR_BACKWARD_END(&but_decorate->block->buttons, but_iter, but_decorate->prev);
+
+ return NULL;
+}
+
void ui_but_anim_decorate_update_from_flag(uiBut *but)
{
- BLI_assert(UI_but_is_decorator(but) && but->prev);
- int flag = but->prev->flag;
+ const uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but);
+
+ if (!but_anim) {
+ printf("Could not find button with matching property to decorate (%s.%s)\n",
+ RNA_struct_identifier(but->rnasearchpoin.type),
+ RNA_property_identifier(but->rnasearchprop));
+ return;
+ }
+
+ int flag = but_anim->flag;
+
if (flag & UI_BUT_DRIVEN) {
but->icon = ICON_DECORATE_DRIVER;
}
@@ -289,22 +321,26 @@ void ui_but_anim_paste_driver(bContext *C)
void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy))
{
wmWindowManager *wm = CTX_wm_manager(C);
- uiBut *but = arg_but;
- but = but->prev;
+ uiBut *but_decorate = arg_but;
+ uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but_decorate);
+
+ if (!but_anim) {
+ return;
+ }
/* FIXME(campbell), swapping active pointer is weak. */
- SWAP(struct uiHandleButtonData *, but->active, but->next->active);
+ SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->active);
wm->op_undo_depth++;
- if (but->flag & UI_BUT_DRIVEN) {
+ if (but_anim->flag & UI_BUT_DRIVEN) {
/* pass */
/* TODO: report? */
}
- else if (but->flag & UI_BUT_ANIMATED_KEY) {
+ else if (but_anim->flag & UI_BUT_ANIMATED_KEY) {
PointerRNA props_ptr;
wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_delete_button", false);
WM_operator_properties_create_ptr(&props_ptr, ot);
- RNA_boolean_set(&props_ptr, "all", but->rnaindex == -1);
+ RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
}
@@ -312,11 +348,11 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy)
PointerRNA props_ptr;
wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_insert_button", false);
WM_operator_properties_create_ptr(&props_ptr, ot);
- RNA_boolean_set(&props_ptr, "all", but->rnaindex == -1);
+ RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
}
- SWAP(struct uiHandleButtonData *, but->active, but->next->active);
+ SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->active);
wm->op_undo_depth--;
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 9a7e189406c..84be109b38e 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -2848,6 +2848,23 @@ static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
return changed;
}
+static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str),
+ const size_t str_step_ofs,
+ const rcti *glyph_step_bounds,
+ const int UNUSED(glyph_advance_x),
+ const rctf *glyph_bounds,
+ const int UNUSED(glyph_bearing[2]),
+ void *user_data)
+{
+ int *cursor_data = user_data;
+ float center = glyph_step_bounds->xmin + (BLI_rctf_size_x(glyph_bounds) / 2.0f);
+ if (cursor_data[0] < center) {
+ cursor_data[1] = str_step_ofs;
+ return false;
+ }
+ return true;
+}
+
/**
* \param x: Screen space cursor location - #wmEvent.x
*
@@ -2883,8 +2900,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
startx += UI_DPI_ICON_SIZE / aspect;
}
}
- /* But this extra .05 makes clicks in between characters feel nicer. */
- startx += ((UI_TEXT_MARGIN_X + 0.05f) * U.widget_unit) / aspect;
+ startx += (UI_TEXT_MARGIN_X * U.widget_unit) / aspect;
/* mouse dragged outside the widget to the left */
if (x < startx) {
@@ -2907,48 +2923,24 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
but->pos = but->ofs;
}
/* mouse inside the widget, mouse coords mapped in widget space */
- else { /* (x >= startx) */
- int pos_i;
-
- /* keep track of previous distance from the cursor to the char */
- float cdist, cdist_prev = 0.0f;
- short pos_prev;
-
- str_last = &str[strlen(str)];
-
- but->pos = pos_prev = ((str_last - str) - but->ofs);
-
- while (true) {
- cdist = startx + BLF_width(fstyle.uifont_id, str + but->ofs, (str_last - str) - but->ofs);
-
- /* check if position is found */
- if (cdist < x) {
- /* check is previous location was in fact closer */
- if ((x - cdist) > (cdist_prev - x)) {
- but->pos = pos_prev;
- }
- break;
- }
- cdist_prev = cdist;
- pos_prev = but->pos;
- /* done with tricky distance checks */
-
- pos_i = but->pos;
- if (but->pos <= 0) {
- break;
- }
- if (BLI_str_cursor_step_prev_utf8(str + but->ofs, but->ofs, &pos_i)) {
- but->pos = pos_i;
- str_last = &str[but->pos + but->ofs];
- }
- else {
- break; /* unlikely but possible */
- }
- }
- but->pos += but->ofs;
- if (but->pos < 0) {
- but->pos = 0;
- }
+ else {
+ str_last = &str[but->ofs];
+ const int str_last_len = strlen(str_last);
+ int x_pos = (int)(x - startx);
+ int glyph_data[2] = {
+ x_pos, /* horizontal position to test. */
+ -1, /* Write the character offset here. */
+ };
+ BLF_boundbox_foreach_glyph(fstyle.uifont_id,
+ str + but->ofs,
+ INT_MAX,
+ ui_textedit_set_cursor_pos_foreach_glyph,
+ glyph_data);
+ /* If value untouched then we are to the right. */
+ if (glyph_data[1] == -1) {
+ glyph_data[1] = str_last_len;
+ }
+ but->pos = glyph_data[1] + but->ofs;
}
if (fstyle.kerning == 1) {
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index f57c775d432..632903448fb 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -2326,6 +2326,9 @@ int UI_idcode_icon_get(const int idcode)
return ICON_WORLD_DATA;
case ID_WS:
return ICON_WORKSPACE;
+ case ID_SIM:
+ /* TODO: Use correct icon. */
+ return ICON_PHYSICS;
default:
return ICON_NONE;
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 51fe990bd02..c2417c86086 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -790,6 +790,11 @@ float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]);
void ui_but_add_shortcut(uiBut *but, const char *key_str, const bool do_strip);
void ui_but_clipboard_free(void);
+bool ui_but_rna_equals(const uiBut *a, const uiBut *b);
+bool ui_but_rna_equals_ex(const uiBut *but,
+ const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ int index);
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
@@ -853,7 +858,7 @@ void ui_draw_menu_item(const struct uiFontStyle *fstyle,
int iconid,
int state,
bool use_sep,
- int *r_name_width);
+ int *r_xmax);
void ui_draw_preview_item(
const struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index cbea32f179a..0609424fd61 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -75,7 +75,7 @@
} \
(void)0
-#define UI_ITEM_PROP_SEP_DIVIDE 0.5f
+#define UI_ITEM_PROP_SEP_DIVIDE 0.4f
/* uiLayoutRoot */
@@ -135,10 +135,11 @@ enum {
UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
UI_ITEM_PROP_SEP = 1 << 3,
+ UI_ITEM_INSIDE_PROP_SEP = 1 << 4,
/* Show an icon button next to each property (to set keyframes, show status).
* Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */
- UI_ITEM_PROP_DECORATE = 1 << 4,
- UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 5,
+ UI_ITEM_PROP_DECORATE = 1 << 5,
+ UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 6,
};
typedef struct uiButtonItem {
@@ -151,8 +152,11 @@ struct uiLayout {
uiLayoutRoot *root;
bContextStore *context;
+ uiLayout *parent;
ListBase items;
+ char heading[UI_MAX_NAME_STR];
+
/** Sub layout to add child items, if not the layout itself. */
uiLayout *child_items_layout;
@@ -1780,6 +1784,7 @@ static void ui_item_rna_size(uiLayout *layout,
PropertyType type;
PropertySubType subtype;
int len, w = 0, h;
+ bool is_checkbox_only = false;
/* arbitrary extended width by type */
type = RNA_property_type(prop);
@@ -1791,6 +1796,10 @@ static void ui_item_rna_size(uiLayout *layout,
name = "non-empty text";
}
else if (type == PROP_BOOLEAN) {
+ if (icon == ICON_NONE) {
+ /* Exception for checkboxes, they need a little less space to align nicely. */
+ is_checkbox_only = true;
+ }
icon = ICON_DOT;
}
else if (type == PROP_ENUM) {
@@ -1850,6 +1859,9 @@ static void ui_item_rna_size(uiLayout *layout,
if (type == PROP_BOOLEAN && name[0]) {
w += UI_UNIT_X / 5;
}
+ else if (is_checkbox_only) {
+ w -= UI_UNIT_X / 4;
+ }
else if (type == PROP_ENUM && !icon_only) {
w += UI_UNIT_X / 4;
}
@@ -1862,6 +1874,57 @@ static void ui_item_rna_size(uiLayout *layout,
*r_h = h;
}
+static bool ui_item_rna_is_expand(PropertyRNA *prop, int index, int item_flag)
+{
+ const bool is_array = RNA_property_array_check(prop);
+ const int subtype = RNA_property_subtype(prop);
+ return is_array && (index == RNA_NO_INDEX) &&
+ ((item_flag & UI_ITEM_R_EXPAND) ||
+ !ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION));
+}
+
+/**
+ * Find first layout ancestor (or self) with a heading set.
+ *
+ * \returns the layout to add the heading to as fallback (i.e. if it can't be placed in a split
+ * layout). Its #uiLayout.heading member can be cleared to mark the heading as added (so
+ * it's not added multiple times). Returns a pointer to the heading
+ */
+static uiLayout *ui_layout_heading_find(uiLayout *cur_layout)
+{
+ for (uiLayout *parent = cur_layout; parent; parent = parent->parent) {
+ if (parent->heading[0]) {
+ return parent;
+ }
+ }
+
+ return NULL;
+}
+
+static void ui_layout_heading_label_add(uiLayout *layout,
+ uiLayout *heading_layout,
+ bool right_align,
+ bool respect_prop_split)
+{
+ const int prev_alignment = layout->alignment;
+
+ if (right_align) {
+ uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_RIGHT);
+ }
+
+ if (respect_prop_split) {
+ uiItemL_respect_property_split(layout, heading_layout->heading, ICON_NONE);
+ }
+ else {
+ uiItemL(layout, heading_layout->heading, ICON_NONE);
+ }
+ /* After adding the heading label, we have to mark it somehow as added, so it's not added again
+ * for other items in this layout. For now just clear it. */
+ heading_layout->heading[0] = '\0';
+
+ layout->alignment = prev_alignment;
+}
+
/**
* Hack to add further items in a row into the second part of the split layout, so the label part
* keeps a fixed size.
@@ -1869,7 +1932,14 @@ static void ui_item_rna_size(uiLayout *layout,
*/
static uiLayout *ui_item_prop_split_layout_hack(uiLayout *layout_parent, uiLayout *layout_split)
{
+ /* Tag item as using property split layout, this is inherited to children so they can get special
+ * treatment if needed. */
+ layout_parent->item.flag |= UI_ITEM_INSIDE_PROP_SEP;
+
if (layout_parent->item.type == ITEM_LAYOUT_ROW) {
+ /* Prevent further splits within the row. */
+ uiLayoutSetPropSep(layout_parent, false);
+
layout_parent->child_items_layout = uiLayoutRow(layout_split, true);
return layout_parent->child_items_layout;
}
@@ -1888,13 +1958,18 @@ void uiItemFullR(uiLayout *layout,
uiBlock *block = layout->root->block;
char namestr[UI_MAX_NAME_STR];
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
-
- /* By default 'use_prop_sep' uses a separate column for labels.
- * This is an exception for check-boxes otherwise only the small checkbox region is clickable.
+ const bool inside_prop_sep = ((layout->item.flag & UI_ITEM_INSIDE_PROP_SEP) != 0);
+ /* Columns can define a heading to insert. If the first item added to a split layout doesn't have
+ * a label to display in the first column, the heading is inserted there. Otherwise it's inserted
+ * as a new row before the first item. */
+ uiLayout *heading_layout = ui_layout_heading_find(layout);
+ /* Although checkboxes use the split layout, they are an exception and should only place their
+ * label in the second column, to not make that almost empty.
*
* Keep using 'use_prop_sep' instead of disabling it entirely because
* we need the ability to have decorators still. */
bool use_prop_sep_split_label = use_prop_sep;
+ bool use_split_empty_name = (flag & UI_ITEM_R_SPLIT_EMPTY_NAME);
#ifdef UI_PROP_DECORATE
struct {
@@ -2005,6 +2080,9 @@ void uiItemFullR(uiLayout *layout,
if (use_prop_sep) {
if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) {
use_prop_sep_split_label = false;
+ /* For checkboxes we make an expection: We allow showing them in a split row even without
+ * label. It typically relates to its neighbor items, so no need for an extra label. */
+ use_split_empty_name = true;
}
}
#endif
@@ -2031,6 +2109,7 @@ void uiItemFullR(uiLayout *layout,
/* Split the label / property. */
uiLayout *layout_parent = layout;
+
if (use_prop_sep) {
uiLayout *layout_row = NULL;
#ifdef UI_PROP_DECORATE
@@ -2041,21 +2120,26 @@ void uiItemFullR(uiLayout *layout,
}
#endif /* UI_PROP_DECORATE */
- if ((name[0] == '\0') || (use_prop_sep_split_label == false)) {
+ if ((name[0] == '\0') && !use_split_empty_name) {
/* Ensure we get a column when text is not set. */
layout = uiLayoutColumn(layout_row ? layout_row : layout, true);
layout->space = 0;
+ if (heading_layout) {
+ ui_layout_heading_label_add(layout, heading_layout, false, false);
+ }
}
else {
- const PropertySubType subtype = RNA_property_subtype(prop);
uiLayout *layout_split = uiLayoutSplit(
layout_row ? layout_row : layout, UI_ITEM_PROP_SEP_DIVIDE, true);
+ bool label_added = false;
layout_split->space = 0;
uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
layout_sub->space = 0;
- if ((index == RNA_NO_INDEX && is_array) &&
- ((!expand && ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION)) == 0)) {
+ if (!use_prop_sep_split_label) {
+ /* Pass */
+ }
+ else if (ui_item_rna_is_expand(prop, index, flag)) {
char name_with_suffix[UI_MAX_DRAW_STR + 2];
char str[2] = {'\0'};
for (int a = 0; a < len; a++) {
@@ -2084,6 +2168,8 @@ void uiItemFullR(uiLayout *layout,
"");
but->drawflag |= UI_BUT_TEXT_RIGHT;
but->drawflag &= ~UI_BUT_TEXT_LEFT;
+
+ label_added = true;
}
}
else {
@@ -2092,13 +2178,17 @@ void uiItemFullR(uiLayout *layout,
block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
but->drawflag |= UI_BUT_TEXT_RIGHT;
but->drawflag &= ~UI_BUT_TEXT_LEFT;
+
+ label_added = true;
}
}
- if (layout_parent) {
- layout_split = ui_item_prop_split_layout_hack(layout_parent, layout_split);
+ if (!label_added && heading_layout) {
+ ui_layout_heading_label_add(layout_sub, heading_layout, true, false);
}
+ layout_split = ui_item_prop_split_layout_hack(layout_parent, layout_split);
+
/* Watch out! We can only write into the new layout now. */
if ((type == PROP_ENUM) && (flag & UI_ITEM_R_EXPAND)) {
/* Expanded enums each have their own name. */
@@ -2113,7 +2203,9 @@ void uiItemFullR(uiLayout *layout,
}
}
else {
- name = "";
+ if (use_prop_sep_split_label) {
+ name = "";
+ }
layout = uiLayoutColumn(layout_split, true);
}
layout->space = 0;
@@ -2132,9 +2224,20 @@ void uiItemFullR(uiLayout *layout,
#endif /* UI_PROP_DECORATE */
}
/* End split. */
+ else if (heading_layout) {
+ /* Could not add heading to split layout, fallback to inserting it to the layout with the
+ * heading itself. */
+ ui_layout_heading_label_add(heading_layout, heading_layout, false, false);
+ }
/* array property */
if (index == RNA_NO_INDEX && is_array) {
+ if (inside_prop_sep) {
+ /* Within a split row, add array items to a column so they match the column layout of
+ * previous items (e.g. transform vector with lock icon for each item). */
+ layout = uiLayoutColumn(layout, true);
+ }
+
ui_item_array(layout,
block,
name,
@@ -2214,12 +2317,6 @@ void uiItemFullR(uiLayout *layout,
if (layout->activate_init) {
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
}
-
- if (use_prop_sep && (use_prop_sep_split_label == false)) {
- /* When the button uses it's own text right align it. */
- but->drawflag |= UI_BUT_TEXT_RIGHT;
- but->drawflag &= ~UI_BUT_TEXT_LEFT;
- }
}
/* The resulting button may have the icon set since boolean button drawing
@@ -2242,50 +2339,21 @@ void uiItemFullR(uiLayout *layout,
#ifdef UI_PROP_DECORATE
if (ui_decorate.use_prop_decorate) {
- const bool is_anim = RNA_property_animateable(ptr, prop);
uiBut *but_decorate = ui_decorate.but ? ui_decorate.but->next : block->buttons.first;
+ const bool use_blank_decorator = (flag & UI_ITEM_R_FORCE_BLANK_DECORATE);
uiLayout *layout_col = uiLayoutColumn(ui_decorate.layout, false);
layout_col->space = 0;
layout_col->emboss = UI_EMBOSS_NONE;
+
int i;
for (i = 0; i < ui_decorate.len && but_decorate; i++) {
+ PointerRNA *ptr_dec = use_blank_decorator ? NULL : &but_decorate->rnapoin;
+ PropertyRNA *prop_dec = use_blank_decorator ? NULL : but_decorate->rnaprop;
+
/* The icons are set in 'ui_but_anim_flag' */
- if (is_anim) {
- but = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_DOT,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Animate property"));
- UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL);
- but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
- }
- else {
- /* We may show other information here in future, for now use empty space. */
- but = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_BLANK1,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- "");
- but->flag |= UI_BUT_DISABLED;
- }
+ uiItemDecoratorR_prop(layout_col, ptr_dec, prop_dec, but_decorate->rnaindex);
+ but = block->buttons.last;
+
/* Order the decorator after the button we decorate, this is used so we can always
* do a quick lookup. */
BLI_remlink(&block->buttons, but);
@@ -2759,6 +2827,7 @@ static uiBut *ui_item_menu(uiLayout *layout,
bool force_menu)
{
uiBlock *block = layout->root->block;
+ uiLayout *heading_layout = ui_layout_heading_find(layout);
uiBut *but;
int w, h;
@@ -2788,6 +2857,10 @@ static uiBut *ui_item_menu(uiLayout *layout,
}
}
+ if (heading_layout) {
+ ui_layout_heading_label_add(layout, heading_layout, true, true);
+ }
+
if (name[0] && icon) {
but = uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip);
}
@@ -2861,6 +2934,91 @@ void uiItemMContents(uiLayout *layout, const char *menuname)
UI_menutype_draw(C, mt, layout);
}
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop.
+ */
+void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ uiBlock *block = layout->root->block;
+ uiBut *but = NULL;
+
+ uiLayout *col;
+ UI_block_layout_set_current(block, layout);
+ col = uiLayoutColumn(layout, false);
+ col->space = 0;
+ col->emboss = UI_EMBOSS_NONE;
+
+ if (ELEM(NULL, ptr, prop) || !RNA_property_animateable(ptr, prop)) {
+ but = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_BLANK1,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ "");
+ but->flag |= UI_BUT_DISABLED;
+ return;
+ }
+
+ const bool is_expand = ui_item_rna_is_expand(prop, index, 0);
+ const bool is_array = RNA_property_array_check(prop);
+
+ /* Loop for the array-case, but only do in case of an expanded array. */
+ for (int i = 0; i < (is_expand ? RNA_property_array_length(ptr, prop) : 1); i++) {
+ but = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_DOT,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Animate property"));
+ UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL);
+ but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
+ /* Reusing RNA search members, setting actual RNA data has many side-effects. */
+ but->rnasearchpoin = *ptr;
+ but->rnasearchprop = prop;
+ /* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */
+ but->custom_data = POINTER_FROM_INT((!is_array || is_expand) ? i : index);
+ }
+}
+
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname.
+ */
+void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index)
+{
+ PropertyRNA *prop = NULL;
+
+ if (ptr && propname) {
+ /* validate arguments */
+ prop = RNA_struct_find_property(ptr, propname);
+ if (!prop) {
+ ui_item_disabled(layout, propname);
+ RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+ }
+
+ /* ptr and prop are allowed to be NULL here. */
+ uiItemDecoratorR_prop(layout, ptr, prop, index);
+}
+
/* popover */
void uiItemPopoverPanel_ptr(
uiLayout *layout, bContext *C, PanelType *pt, const char *name, int icon)
@@ -3004,33 +3162,40 @@ void uiItemL(uiLayout *layout, const char *name, int icon)
}
/**
- * Helper to add a label, which handles logic for split property layout if needed.
- *
- * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where we may
- * want to use the logic. For those this helper was added, although it will likely have to be
- * extended to support more cases.
- * Ideally, #uiItemFullR() could just call this, but it currently has too many special needs.
- *
- * \return A layout placed in the row after the split layout. Used to place decorator items.
+ * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the
+ * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many
+ * special needs.
+ */
+uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
+{
+ uiPropertySplitWrapper split_wrapper = {NULL};
+
+ uiLayout *layout_row = uiLayoutRow(parent_layout, true);
+ uiLayout *layout_split = uiLayoutSplit(layout_row, UI_ITEM_PROP_SEP_DIVIDE, true);
+
+ layout_split->space = 0;
+ split_wrapper.label_column = uiLayoutColumn(layout_split, true);
+ split_wrapper.label_column->alignment = UI_LAYOUT_ALIGN_RIGHT;
+ split_wrapper.property_row = ui_item_prop_split_layout_hack(parent_layout, layout_split);
+ split_wrapper.decorate_column = uiLayoutColumn(layout_row, true);
+
+ return split_wrapper;
+}
+
+/*
+ * Helper to add a label and creates a property split layout if needed.
*/
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon)
{
if (layout->item.flag & UI_ITEM_PROP_SEP) {
uiBlock *block = uiLayoutGetBlock(layout);
- uiLayout *layout_row = uiLayoutRow(layout, true);
- uiLayout *layout_split = uiLayoutSplit(layout_row, UI_ITEM_PROP_SEP_DIVIDE, true);
- uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
-
- layout_split->space = layout_sub->space = layout_row->space = 0;
- layout_sub->alignment = UI_LAYOUT_ALIGN_RIGHT;
-
- uiItemL_(layout_sub, text, icon);
+ uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(layout);
+ /* Further items added to 'layout' will automatically be added to split_wrapper.property_row */
- layout_split = ui_item_prop_split_layout_hack(layout, layout_split);
- UI_block_layout_set_current(block, layout_split);
+ uiItemL_(split_wrapper.label_column, text, icon);
+ UI_block_layout_set_current(block, split_wrapper.property_row);
- /* Give caller a new sub-row to place items in. */
- return layout_row;
+ return split_wrapper.decorate_column;
}
else {
char namestr[UI_MAX_NAME_STR];
@@ -4471,13 +4636,24 @@ static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int ali
litem->redalert = layout->redalert;
litem->w = layout->w;
litem->emboss = layout->emboss;
- litem->item.flag = (layout->item.flag & (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE));
+ litem->item.flag = (layout->item.flag &
+ (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE | UI_ITEM_INSIDE_PROP_SEP));
if (layout->child_items_layout) {
BLI_addtail(&layout->child_items_layout->items, litem);
+ litem->parent = layout->child_items_layout;
}
else {
BLI_addtail(&layout->items, litem);
+ litem->parent = layout;
+ }
+}
+
+static void ui_layout_heading_set(uiLayout *layout, const char *heading)
+{
+ BLI_assert(layout->heading[0] == '\0');
+ if (heading) {
+ STRNCPY(layout->heading, heading);
}
}
@@ -4497,6 +4673,16 @@ uiLayout *uiLayoutRow(uiLayout *layout, bool align)
return litem;
}
+/**
+ * See #uiLayoutColumnWithHeading().
+ */
+uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
+{
+ uiLayout *litem = uiLayoutRow(layout, align);
+ ui_layout_heading_set(litem, heading);
+ return litem;
+}
+
uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
{
uiLayout *litem;
@@ -4512,6 +4698,19 @@ uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
return litem;
}
+/**
+ * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is
+ * added through #uiItemFullR(). If split layout is used and the item has no string to add to the
+ * first split-column, the heading is added there instead. Otherwise the heading inserted with a
+ * new row.
+ */
+uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading)
+{
+ uiLayout *litem = uiLayoutColumn(layout, align);
+ ui_layout_heading_set(litem, heading);
+ return litem;
+}
+
uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align)
{
uiLayoutItemFlow *flow;
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 2ad1c25305c..04179721305 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -102,6 +102,7 @@ typedef struct uiHandlePanelData {
double starttime;
/* dragging */
+ bool is_drag_drop;
int startx, starty;
int startofsx, startofsy;
int startsizex, startsizey;
@@ -743,7 +744,7 @@ void ui_draw_aligned_panel(uiStyle *style,
/* an open panel */
else {
/* in some occasions, draw a border */
- if (panel->flag & PNL_SELECT) {
+ if (panel->flag & PNL_SELECT && !is_subpanel) {
if (panel->control & UI_PNL_SOLID) {
UI_draw_roundbox_corner_set(UI_CNR_ALL);
}
@@ -876,6 +877,16 @@ static int get_panel_real_ofsx(Panel *panel)
}
}
+bool UI_panel_is_dragging(const struct Panel *panel)
+{
+ uiHandlePanelData *data = panel->activedata;
+ if (!data) {
+ return false;
+ }
+
+ return data->is_drag_drop;
+}
+
typedef struct PanelSort {
Panel *panel, *orig;
} PanelSort;
@@ -2458,6 +2469,24 @@ static void ui_handler_remove_panel(bContext *C, void *userdata)
panel_activate_state(C, panel, PANEL_STATE_EXIT);
}
+/**
+ * Set selection state for a panel and its subpanels. The subpanels need to know they are selected
+ * too so they can be drawn above their parent when it is dragged.
+ */
+static void set_panel_selection(Panel *panel, bool value)
+{
+ if (value) {
+ panel->flag |= PNL_SELECT;
+ }
+ else {
+ panel->flag &= ~PNL_SELECT;
+ }
+
+ LISTBASE_FOREACH (Panel *, child, &panel->children) {
+ set_panel_selection(child, value);
+ }
+}
+
static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state)
{
uiHandlePanelData *data = panel->activedata;
@@ -2468,6 +2497,8 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
return;
}
+ bool was_drag_drop = (data && data->state == PANEL_STATE_DRAG);
+
if (state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) {
if (data && data->state != PANEL_STATE_ANIMATION) {
/* XXX:
@@ -2480,10 +2511,10 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
check_panel_overlap(region, NULL); /* clears */
}
- panel->flag &= ~PNL_SELECT;
+ set_panel_selection(panel, false);
}
else {
- panel->flag |= PNL_SELECT;
+ set_panel_selection(panel, true);
}
if (data && data->animtimer) {
@@ -2519,6 +2550,12 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
data->startsizex = panel->sizex;
data->startsizey = panel->sizey;
data->starttime = PIL_check_seconds_timer();
+
+ /* Remember drag drop state even when animating to the aligned position after dragging. */
+ data->is_drag_drop = was_drag_drop;
+ if (state == PANEL_STATE_DRAG) {
+ data->is_drag_drop = true;
+ }
}
ED_region_tag_redraw(region);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index ca9f12a4219..2d1b3f560f7 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -688,6 +688,8 @@ static const char *template_id_browse_tip(const StructRNA *type)
return N_("Browse Point Cloud Data to be linked");
case ID_VO:
return N_("Browse Volume Data to be linked");
+ case ID_SIM:
+ return N_("Browse Simulation to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -753,7 +755,8 @@ static uiBut *template_id_def_new_but(uiBlock *block,
BLT_I18NCONTEXT_ID_LIGHTPROBE,
BLT_I18NCONTEXT_ID_HAIR,
BLT_I18NCONTEXT_ID_POINTCLOUD,
- BLT_I18NCONTEXT_ID_VOLUME, );
+ BLT_I18NCONTEXT_ID_VOLUME,
+ BLT_I18NCONTEXT_ID_SIMULATION, );
/* Note: BLT_I18N_MSGID_MULTI_CTXT takes a maximum number of parameters,
* check the definition to see if a new call must be added when the limit
* is exceeded. */
@@ -1840,20 +1843,26 @@ static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
ED_undo_push(C, "Modifier convert to real");
}
-static int modifier_can_delete(ModifierData *md)
+static bool modifier_can_delete(ModifierData *md)
{
/* fluid particle modifier can't be deleted here */
if (md->type == eModifierType_ParticleSystem) {
short particle_type = ((ParticleSystemModifierData *)md)->psys->part->type;
- if (particle_type == PART_FLUID || particle_type == PART_FLUID_FLIP ||
- particle_type == PART_FLUID_FOAM || particle_type == PART_FLUID_SPRAY ||
- particle_type == PART_FLUID_BUBBLE || particle_type == PART_FLUID_TRACER ||
- particle_type == PART_FLUID_SPRAYFOAM || particle_type == PART_FLUID_SPRAYBUBBLE ||
- particle_type == PART_FLUID_FOAMBUBBLE || particle_type == PART_FLUID_SPRAYFOAMBUBBLE) {
- return 0;
+ if (ELEM(particle_type,
+ PART_FLUID,
+ PART_FLUID_FLIP,
+ PART_FLUID_FOAM,
+ PART_FLUID_SPRAY,
+ PART_FLUID_BUBBLE,
+ PART_FLUID_TRACER,
+ PART_FLUID_SPRAYFOAM,
+ PART_FLUID_SPRAYBUBBLE,
+ PART_FLUID_FOAMBUBBLE,
+ PART_FLUID_SPRAYFOAMBUBBLE)) {
+ return false;
}
}
- return 1;
+ return true;
}
/* Check whether Modifier is a simulation or not,
@@ -2432,21 +2441,196 @@ uiLayout *uiTemplateShaderFx(uiLayout *layout, bContext *UNUSED(C), PointerRNA *
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Operator Redo Buttons Template
+/** \name Operator Property Buttons Template
* \{ */
-static void template_operator_redo_property_buts_draw(
- const bContext *C, wmOperator *op, uiLayout *layout, int layout_flags, bool *r_has_advanced)
+typedef struct uiTemplateOperatorPropertyPollParam {
+ const bContext *C;
+ wmOperator *op;
+ short flag;
+} uiTemplateOperatorPropertyPollParam;
+
+#ifdef USE_OP_RESET_BUT
+static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C),
+ void *op_pt,
+ void *UNUSED(arg_dummy2))
+{
+ WM_operator_properties_reset((wmOperator *)op_pt);
+}
+#endif
+
+static bool ui_layout_operator_buts_poll_property(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *prop,
+ void *user_data)
+{
+ uiTemplateOperatorPropertyPollParam *params = user_data;
+
+ if ((params->flag & UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED) &&
+ (RNA_property_tags(prop) & OP_PROP_TAG_ADVANCED)) {
+ return false;
+ }
+ return params->op->type->poll_property(params->C, params->op, prop);
+}
+
+static eAutoPropButsReturn template_operator_property_buts_draw_single(
+ const bContext *C,
+ wmOperator *op,
+ uiLayout *layout,
+ const eButLabelAlign label_align,
+ int layout_flags)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+ eAutoPropButsReturn return_info = 0;
+
+ if (!op->properties) {
+ IDPropertyTemplate val = {0};
+ op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
+ }
+
+ /* poll() on this operator may still fail,
+ * at the moment there is no nice feedback when this happens just fails silently. */
+ if (!WM_operator_repeat_check(C, op)) {
+ UI_block_lock_set(block, true, "Operator can't' redo");
+ return return_info;
+ }
+ else {
+ /* useful for macros where only one of the steps can't be re-done */
+ UI_block_lock_clear(block);
+ }
+
+ if (layout_flags & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) {
+ uiItemL(layout, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
+ }
+
+ /* menu */
+ if (op->type->flag & OPTYPE_PRESET) {
+ /* XXX, no simple way to get WM_MT_operator_presets.bl_label
+ * from python! Label remains the same always! */
+ PointerRNA op_ptr;
+ uiLayout *row;
+
+ block->ui_operator = op;
+
+ row = uiLayoutRow(layout, true);
+ uiItemM(row, "WM_MT_operator_presets", NULL, ICON_NONE);
+
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
+ uiItemFullO_ptr(row, ot, "", ICON_ADD, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_string_set(&op_ptr, "operator", op->type->idname);
+
+ uiItemFullO_ptr(row, ot, "", ICON_REMOVE, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_string_set(&op_ptr, "operator", op->type->idname);
+ RNA_boolean_set(&op_ptr, "remove_active", true);
+ }
+
+ if (op->type->ui) {
+ op->layout = layout;
+ op->type->ui((bContext *)C, op);
+ op->layout = NULL;
+
+ /* UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too. We could
+ * allow ot.ui callback to return this, but not needed right now. */
+ }
+ else {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ PointerRNA ptr;
+ uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op, .flag = layout_flags};
+ const bool use_prop_split = (layout_flags & UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT) == 0;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ uiLayoutSetPropSep(layout, use_prop_split);
+ uiLayoutSetPropDecorate(layout, false);
+
+ /* main draw call */
+ return_info = uiDefAutoButsRNA(
+ layout,
+ &ptr,
+ op->type->poll_property ? ui_layout_operator_buts_poll_property : NULL,
+ op->type->poll_property ? &user_data : NULL,
+ op->type->prop,
+ label_align,
+ (layout_flags & UI_TEMPLATE_OP_PROPS_COMPACT));
+
+ if ((return_info & UI_PROP_BUTS_NONE_ADDED) &&
+ (layout_flags & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) {
+ uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
+ }
+ }
+
+#ifdef USE_OP_RESET_BUT
+ /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled
+ * but this is not so important if this button is drawn in those cases
+ * (which isn't all that likely anyway) - campbell */
+ if (op->properties->len) {
+ uiBut *but;
+ uiLayout *col; /* needed to avoid alignment errors with previous buttons */
+
+ col = uiLayoutColumn(layout, false);
+ block = uiLayoutGetBlock(col);
+ but = uiDefIconTextBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_FILE_REFRESH,
+ IFACE_("Reset"),
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Reset operator defaults"));
+ UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL);
+ }
+#endif
+
+ /* set various special settings for buttons */
+
+ /* Only do this if we're not refreshing an existing UI. */
+ if (block->oldblock == NULL) {
+ const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
+ uiBut *but;
+
+ for (but = block->buttons.first; but; but = but->next) {
+ /* no undo for buttons for operator redo panels */
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+
+ /* only for popups, see [#36109] */
+
+ /* if button is operator's default property, and a text-field, enable focus for it
+ * - this is used for allowing operators with popups to rename stuff with fewer clicks
+ */
+ if (is_popup) {
+ if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) {
+ UI_but_focus_on_enter_event(CTX_wm_window(C), but);
+ }
+ }
+ }
+ }
+
+ return return_info;
+}
+
+static void template_operator_property_buts_draw_recursive(const bContext *C,
+ wmOperator *op,
+ uiLayout *layout,
+ const eButLabelAlign label_align,
+ int layout_flags,
+ bool *r_has_advanced)
{
if (op->type->flag & OPTYPE_MACRO) {
LISTBASE_FOREACH (wmOperator *, macro_op, &op->macro) {
- template_operator_redo_property_buts_draw(C, macro_op, layout, layout_flags, r_has_advanced);
+ template_operator_property_buts_draw_recursive(
+ C, macro_op, layout, label_align, layout_flags, r_has_advanced);
}
}
else {
/* Might want to make label_align adjustable somehow. */
- eAutoPropButsReturn return_info = uiTemplateOperatorPropertyButs(
- C, layout, op, UI_BUT_LABEL_ALIGN_NONE, layout_flags);
+ eAutoPropButsReturn return_info = template_operator_property_buts_draw_single(
+ C, op, layout, label_align, layout_flags);
if (return_info & UI_PROP_BUTS_ANY_FAILED_CHECK) {
if (r_has_advanced) {
*r_has_advanced = true;
@@ -2455,6 +2639,61 @@ static void template_operator_redo_property_buts_draw(
}
}
+static bool ui_layout_operator_properties_only_booleans(const bContext *C,
+ wmWindowManager *wm,
+ wmOperator *op,
+ int layout_flags)
+{
+ if (op->type->flag & OPTYPE_MACRO) {
+ LISTBASE_FOREACH (wmOperator *, macro_op, &op->macro) {
+ if (!ui_layout_operator_properties_only_booleans(C, wm, macro_op, layout_flags)) {
+ return false;
+ }
+ }
+ }
+ else {
+ uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op, .flag = layout_flags};
+ PointerRNA ptr;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ RNA_STRUCT_BEGIN (&ptr, prop) {
+ if (RNA_property_flag(prop) & PROP_HIDDEN) {
+ continue;
+ }
+ if (op->type->poll_property &&
+ !ui_layout_operator_buts_poll_property(&ptr, prop, &user_data)) {
+ continue;
+ }
+ if (RNA_property_type(prop) != PROP_BOOLEAN) {
+ return false;
+ }
+ }
+ RNA_STRUCT_END;
+ }
+
+ return true;
+}
+
+/**
+ * Draw Operator property buttons for redoing execution with different settings.
+ * This function does not initialize the layout,
+ * functions can be called on the layout before and after.
+ */
+void uiTemplateOperatorPropertyButs(
+ const bContext *C, uiLayout *layout, wmOperator *op, eButLabelAlign label_align, short flag)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ /* If there are only checkbox items, don't use split layout by default. It looks weird if the
+ * checkboxes only use half the width. */
+ if (ui_layout_operator_properties_only_booleans(C, wm, op, flag)) {
+ flag |= UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT;
+ }
+
+ template_operator_property_buts_draw_recursive(C, op, layout, label_align, flag, NULL);
+}
+
void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
{
wmOperator *op = WM_operator_last_redo(C);
@@ -2487,8 +2726,8 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
#endif
UI_block_func_handle_set(block, ED_undo_operator_repeat_cb_evt, op);
- template_operator_redo_property_buts_draw(
- C, op, layout, layout_flags, NULL /* &has_advanced */);
+ template_operator_property_buts_draw_recursive(
+ C, op, layout, UI_BUT_LABEL_ALIGN_NONE, layout_flags, NULL /* &has_advanced */);
/* Warning! this leaves the handle function for any other users of this block. */
#if 0
@@ -6895,6 +7134,49 @@ static void menu_types_add_from_keymap_items(bContext *C,
}
}
+static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data)
+{
+ /* Add to temporary list so we can sort them separately. */
+ ListBase operator_items = {NULL, NULL};
+
+ MemArena *memarena = data->memarena;
+ GHashIterator iter;
+ for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
+ BLI_ghashIterator_step(&iter)) {
+ wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+
+ if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
+ continue;
+ }
+
+ if (WM_operator_poll((bContext *)C, ot)) {
+ const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
+
+ struct MenuSearch_Item *item = NULL;
+ item = BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MENU_SEARCH_TYPE_OP;
+
+ item->op.type = ot;
+ item->op.opcontext = WM_OP_EXEC_DEFAULT;
+ item->op.context = NULL;
+
+ char idname_as_py[OP_MAX_TYPENAME];
+ char uiname[256];
+ WM_operator_py_idname(idname_as_py, ot->idname);
+
+ SNPRINTF(uiname, "%s " MENU_SEP "%s", idname_as_py, ot_ui_name);
+
+ item->drawwstr_full = strdup_memarena(memarena, uiname);
+
+ BLI_addtail(&operator_items, item);
+ }
+ }
+
+ BLI_listbase_sort(&operator_items, menu_item_sort_by_drawstr_full);
+
+ BLI_movelisttolist(&data->items, &operator_items);
+}
+
/**
* Create #MenuSearch_Data by inspecting the current context, this uses two methods:
*
@@ -7208,6 +7490,10 @@ static struct MenuSearch_Data *menu_items_from_ui_create(bContext *C,
data->memarena = memarena;
+ if (U.flag & USER_DEVELOPER_UI) {
+ menu_items_from_all_operators(C, data);
+ }
+
return data;
}
@@ -7348,187 +7634,6 @@ void uiTemplateMenuSearch(uiLayout *layout)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Operator Redo Properties Template
- * \{ */
-
-#ifdef USE_OP_RESET_BUT
-static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C),
- void *op_pt,
- void *UNUSED(arg_dummy2))
-{
- WM_operator_properties_reset((wmOperator *)op_pt);
-}
-#endif
-
-struct uiTemplateOperatorPropertyPollParam {
- const bContext *C;
- wmOperator *op;
- short flag;
-};
-
-static bool ui_layout_operator_buts_poll_property(struct PointerRNA *UNUSED(ptr),
- struct PropertyRNA *prop,
- void *user_data)
-{
- struct uiTemplateOperatorPropertyPollParam *params = user_data;
- if ((params->flag & UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED) &&
- (RNA_property_tags(prop) & OP_PROP_TAG_ADVANCED)) {
- return false;
- }
- return params->op->type->poll_property(params->C, params->op, prop);
-}
-
-/**
- * Draw Operator property buttons for redoing execution with different settings.
- * This function does not initialize the layout,
- * functions can be called on the layout before and after.
- */
-eAutoPropButsReturn uiTemplateOperatorPropertyButs(const bContext *C,
- uiLayout *layout,
- wmOperator *op,
- const eButLabelAlign label_align,
- const short flag)
-{
- uiBlock *block = uiLayoutGetBlock(layout);
- eAutoPropButsReturn return_info = 0;
-
- if (!op->properties) {
- IDPropertyTemplate val = {0};
- op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
- }
-
- /* poll() on this operator may still fail,
- * at the moment there is no nice feedback when this happens just fails silently. */
- if (!WM_operator_repeat_check(C, op)) {
- UI_block_lock_set(block, true, "Operator can't' redo");
- return return_info;
- }
- else {
- /* useful for macros where only one of the steps can't be re-done */
- UI_block_lock_clear(block);
- }
-
- if (flag & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) {
- uiItemL(layout, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
- }
-
- /* menu */
- if (op->type->flag & OPTYPE_PRESET) {
- /* XXX, no simple way to get WM_MT_operator_presets.bl_label
- * from python! Label remains the same always! */
- PointerRNA op_ptr;
- uiLayout *row;
-
- block->ui_operator = op;
-
- row = uiLayoutRow(layout, true);
- uiItemM(row, "WM_MT_operator_presets", NULL, ICON_NONE);
-
- wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
- uiItemFullO_ptr(row, ot, "", ICON_ADD, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_string_set(&op_ptr, "operator", op->type->idname);
-
- uiItemFullO_ptr(row, ot, "", ICON_REMOVE, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_string_set(&op_ptr, "operator", op->type->idname);
- RNA_boolean_set(&op_ptr, "remove_active", true);
- }
-
- if (op->type->ui) {
- op->layout = layout;
- op->type->ui((bContext *)C, op);
- op->layout = NULL;
-
- /* UI_LAYOUT_OP_SHOW_EMPTY ignored. return_info is ignored too. We could
- * allow ot.ui callback to return this, but not needed right now. */
- }
- else {
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
- struct uiTemplateOperatorPropertyPollParam user_data = {
- .C = C,
- .op = op,
- .flag = flag,
- };
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
-
- /* main draw call */
- return_info = uiDefAutoButsRNA(
- layout,
- &ptr,
- op->type->poll_property ? ui_layout_operator_buts_poll_property : NULL,
- op->type->poll_property ? &user_data : NULL,
- op->type->prop,
- label_align,
- (flag & UI_TEMPLATE_OP_PROPS_COMPACT));
-
- if ((return_info & UI_PROP_BUTS_NONE_ADDED) && (flag & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) {
- uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
- }
- }
-
-#ifdef USE_OP_RESET_BUT
- /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled
- * but this is not so important if this button is drawn in those cases
- * (which isn't all that likely anyway) - campbell */
- if (op->properties->len) {
- uiBut *but;
- uiLayout *col; /* needed to avoid alignment errors with previous buttons */
-
- col = uiLayoutColumn(layout, false);
- block = uiLayoutGetBlock(col);
- but = uiDefIconTextBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_FILE_REFRESH,
- IFACE_("Reset"),
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Reset operator defaults"));
- UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL);
- }
-#endif
-
- /* set various special settings for buttons */
-
- /* Only do this if we're not refreshing an existing UI. */
- if (block->oldblock == NULL) {
- const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
- uiBut *but;
-
- for (but = block->buttons.first; but; but = but->next) {
- /* no undo for buttons for operator redo panels */
- UI_but_flag_disable(but, UI_BUT_UNDO);
-
- /* only for popups, see [#36109] */
-
- /* if button is operator's default property, and a text-field, enable focus for it
- * - this is used for allowing operators with popups to rename stuff with fewer clicks
- */
- if (is_popup) {
- if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) {
- UI_but_focus_on_enter_event(CTX_wm_window(C), but);
- }
- }
- }
- }
-
- return return_info;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Running Jobs Template
* \{ */
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 79a90d27373..d8c168a1423 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -294,7 +294,7 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
const bool compact)
{
eAutoPropButsReturn return_info = UI_PROP_BUTS_NONE_ADDED;
- uiLayout *split, *col;
+ uiLayout *col;
const char *name;
RNA_STRUCT_BEGIN (ptr, prop) {
@@ -325,19 +325,11 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
}
else {
BLI_assert(label_align == UI_BUT_LABEL_ALIGN_SPLIT_COLUMN);
- split = uiLayoutSplit(layout, 0.5f, false);
-
- col = uiLayoutColumn(split, false);
- uiItemL(col, (is_boolean) ? "" : name, ICON_NONE);
- col = uiLayoutColumn(split, false);
+ col = uiLayoutColumn(layout, true);
+ /* Let uiItemFullR() create the split layout. */
+ uiLayoutSetPropSep(col, true);
}
- /* May need to add more cases here.
- * don't override enum flag names */
-
- /* name is shown above, empty name for button below */
- name = (flag & PROP_ENUM_FLAG || is_boolean) ? NULL : "";
-
break;
}
case UI_BUT_LABEL_ALIGN_NONE:
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 2ac84b4b043..0d4eff2ba31 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -42,6 +42,8 @@
#include "BLF_api.h"
+#include "ED_node.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
@@ -2093,15 +2095,18 @@ static void widget_draw_text_ime_underline(const uiFontStyle *fstyle,
#endif /* WITH_INPUT_IME */
static bool widget_draw_text_underline_calc_center_x(const char *UNUSED(str),
- const size_t str_ofs,
- const rcti *glyph_bounds,
- const int glyph_advance_x,
+ const size_t str_step_ofs,
+ const rcti *glyph_step_bounds,
+ const int UNUSED(glyph_advance_x),
+ const rctf *glyph_bounds,
+ const int glyph_bearing[2],
void *user_data)
{
/* The index of the character to get, set to the x-position. */
int *ul_data = user_data;
- if (ul_data[0] == (int)str_ofs) {
- ul_data[1] = glyph_bounds->xmin + (glyph_advance_x / 2);
+ if (ul_data[0] == (int)str_step_ofs) {
+ ul_data[1] = glyph_step_bounds->xmin + glyph_bearing[0] +
+ (BLI_rctf_size_x(glyph_bounds) / 2.0f);
/* Early exit. */
return false;
}
@@ -2419,6 +2424,30 @@ static void widget_draw_extra_icons(const uiWidgetColors *wcol,
}
}
+static void widget_draw_node_link_socket(const uiWidgetColors *wcol,
+ const rcti *rect,
+ uiBut *but,
+ float alpha)
+{
+ /* Node socket pointer can be passed as custom_data, see UI_but_node_link_set(). */
+ if (but->custom_data) {
+ const float scale = 0.9f / but->block->aspect;
+
+ float col[4];
+ rgba_uchar_to_float(col, but->col);
+ col[3] *= alpha;
+
+ GPU_blend(true);
+ UI_widgetbase_draw_cache_flush();
+ GPU_blend(false);
+
+ ED_node_socket_draw(but->custom_data, rect, col, scale);
+ }
+ else {
+ widget_draw_icon(but, ICON_LAYER_USED, alpha, rect, wcol->text);
+ }
+}
+
/* draws text and icons for buttons */
static void widget_draw_text_icon(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
@@ -2428,15 +2457,27 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
+ bool no_text_padding = but->drawflag & UI_BUT_NO_TEXT_PADDING;
ui_but_text_password_hide(password_str, but, false);
/* check for button text label */
if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_POPOVER) && (but->flag & UI_BUT_NODE_LINK)) {
rcti temp = *rect;
- temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
- widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, wcol->text);
- rect->xmax = temp.xmin;
+ const int size = BLI_rcti_size_y(rect) + 1; /* Not the icon size! */
+
+ if (but->drawflag & UI_BUT_ICON_LEFT) {
+ temp.xmax = rect->xmin + size;
+ rect->xmin = temp.xmax;
+ /* Further padding looks off. */
+ no_text_padding = true;
+ }
+ else {
+ temp.xmin = rect->xmax - size;
+ rect->xmax = temp.xmin;
+ }
+
+ widget_draw_node_link_socket(wcol, &temp, but, alpha);
}
/* If there's an icon too (made with uiDefIconTextBut) then draw the icon
@@ -2521,28 +2562,30 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
rect->xmin += icon_size + icon_padding;
}
- int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
- if (but->editstr) {
- rect->xmin += text_padding;
- }
- else if (but->flag & UI_BUT_DRAG_MULTI) {
- bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL;
- if (text_is_edited) {
+ if (!no_text_padding) {
+ int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
+ if (but->editstr) {
rect->xmin += text_padding;
}
- }
- else if (but->drawflag & UI_BUT_TEXT_LEFT) {
-
- /* Reduce the left padding for labels without an icon. */
- if ((but->type == UI_BTYPE_LABEL) && !(but->flag & UI_HAS_ICON) &&
- !ui_block_is_menu(but->block)) {
- text_padding /= 2;
+ else if (but->flag & UI_BUT_DRAG_MULTI) {
+ bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL;
+ if (text_is_edited) {
+ rect->xmin += text_padding;
+ }
}
+ else if (but->drawflag & UI_BUT_TEXT_LEFT) {
- rect->xmin += text_padding;
- }
- else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
- rect->xmax -= text_padding;
+ /* Reduce the left padding for labels without an icon. */
+ if ((but->type == UI_BTYPE_LABEL) && !(but->flag & UI_HAS_ICON) &&
+ !ui_block_is_menu(but->block)) {
+ text_padding /= 2;
+ }
+
+ rect->xmin += text_padding;
+ }
+ else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
+ rect->xmax -= text_padding;
+ }
}
/* Menu contains sub-menu items with triangle icon on their right. Shortcut
@@ -4146,10 +4189,10 @@ static void widget_optionbut(uiWidgetColors *wcol,
/* smaller */
delta = 1 + BLI_rcti_size_y(&recttemp) / 8;
- recttemp.xmin += delta;
- recttemp.ymin += delta;
- recttemp.xmax -= delta;
- recttemp.ymax -= delta;
+ BLI_rcti_resize(
+ &recttemp, BLI_rcti_size_x(&recttemp) - delta * 2, BLI_rcti_size_y(&recttemp) - delta * 2);
+ /* Keep one edge in place. */
+ BLI_rcti_translate(&recttemp, text_before_widget ? delta : -delta, 0);
rad = wcol->roundness * BLI_rcti_size_y(&recttemp);
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
@@ -4161,13 +4204,13 @@ static void widget_optionbut(uiWidgetColors *wcol,
widgetbase_draw(&wtb, wcol);
- /* text space */
- const float offset = BLI_rcti_size_y(rect) * 0.7 + delta;
+ /* Text space - factor is really just eyeballed. */
+ const float offset = delta * 0.9;
if (text_before_widget) {
- rect->xmax -= offset;
+ rect->xmax = recttemp.xmin - offset;
}
else {
- rect->xmin += offset;
+ rect->xmin = recttemp.xmax + offset;
}
}
@@ -4724,9 +4767,14 @@ void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but,
case UI_BTYPE_CHECKBOX_N:
if (!(but->flag & UI_HAS_ICON)) {
wt = widget_type(UI_WTYPE_CHECKBOX);
+
if ((but->drawflag & (UI_BUT_TEXT_LEFT | UI_BUT_TEXT_RIGHT)) == 0) {
but->drawflag |= UI_BUT_TEXT_LEFT;
}
+ /* widget_optionbut() carefully sets the text rectangle for fine tuned paddings. If the
+ * text drawing were to add its own padding, DPI and zoom factor would be applied twice
+ * in the final padding, so it's difficult to control it. */
+ but->drawflag |= UI_BUT_NO_TEXT_PADDING;
}
else {
wt = widget_type(UI_WTYPE_TOGGLE);
@@ -5277,15 +5325,23 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl
wt->draw(&wt->wcol, rect, 0, 0);
}
-/* helper call to draw a menu item without button */
-/* state: UI_ACTIVE or 0 */
+/**
+ * Helper call to draw a menu item without a button.
+ *
+ * \param state: The state of the button,
+ * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
+ * \param use_sep: When true, characters after the last #UI_SEP_CHAR are right aligned,
+ * use for displaying key shortcuts.
+ * \param r_xmax: The right hand position of the text, this takes into the icon,
+ * padding and text clipping when there is not enough room to display the full text.
+ */
void ui_draw_menu_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
int state,
bool use_sep,
- int *r_name_width)
+ int *r_xmax)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
rcti _rect = *rect;
@@ -5348,8 +5404,8 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
&xofs,
&yofs,
&info);
- if (r_name_width != NULL) {
- *r_name_width = xofs + info.width;
+ if (r_xmax != NULL) {
+ *r_xmax = xofs + info.width;
}
}
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index c07166b9ad2..f8419ba3eba 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -60,7 +60,7 @@
#include "interface_intern.h"
-static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers);
+static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize);
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
@@ -134,7 +134,7 @@ void UI_view2d_mask_from_win(const View2D *v2d, rcti *r_mask)
*
* \param mask_scroll: Optionally clamp scrollbars by this region.
*/
-static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scroll)
+static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
{
int scroll;
@@ -144,26 +144,24 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr
mask_scroll = &v2d->mask;
}
- if (check_scrollers) {
- /* check size if hiding flag is set: */
- if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) {
- if (!(v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES)) {
- if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) {
- v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR;
- }
- else {
- v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR;
- }
+ /* check size if hiding flag is set: */
+ if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) {
+ if (!(v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES)) {
+ if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) {
+ v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR;
+ }
+ else {
+ v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR;
}
}
- if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) {
- if (!(v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES)) {
- if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) {
- v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR;
- }
- else {
- v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR;
- }
+ }
+ if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) {
+ if (!(v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES)) {
+ if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) {
+ v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR;
+ }
+ else {
+ v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR;
}
}
}
@@ -385,8 +383,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
v2d->winx = winx;
v2d->winy = winy;
- /* set masks (always do), but leave scroller scheck to totrect_set */
- view2d_masks(v2d, 0, NULL);
+ view2d_masks(v2d, NULL);
if (do_init) {
/* Visible by default. */
@@ -394,13 +391,12 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
}
/* set 'tot' rect before setting cur? */
- /* XXX confusing stuff here still -
- * I made this function not check scroller hide - that happens in totrect_set */
+ /* XXX confusing stuff here still */
if (tot_changed) {
UI_view2d_totRect_set_resize(v2d, winx, winy, !do_init);
}
else {
- ui_view2d_curRect_validate_resize(v2d, !do_init, 0);
+ ui_view2d_curRect_validate_resize(v2d, !do_init);
}
}
@@ -409,7 +405,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
* 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot'
*/
// XXX pre2.5 -> this used to be called test_view2d()
-static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers)
+static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize)
{
float totwidth, totheight, curwidth, curheight, width, height;
float winx, winy;
@@ -851,12 +847,12 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mas
}
/* set masks */
- view2d_masks(v2d, mask_scrollers, NULL);
+ view2d_masks(v2d, NULL);
}
void UI_view2d_curRect_validate(View2D *v2d)
{
- ui_view2d_curRect_validate_resize(v2d, 0, 1);
+ ui_view2d_curRect_validate_resize(v2d, false);
}
/* ------------------ */
@@ -982,22 +978,10 @@ void UI_view2d_curRect_reset(View2D *v2d)
/* Change the size of the maximum viewable area (i.e. 'tot' rect) */
void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resize)
{
- // int scroll = view2d_scroll_mapped(v2d->scroll);
-
/* don't do anything if either value is 0 */
width = abs(width);
height = abs(height);
- /* hrumf! */
- /* XXX: there are work arounds for this in the panel and file browse code. */
- /* round to int, because this is called with width + V2D_SCROLL_WIDTH */
- // if (scroll & V2D_SCROLL_HORIZONTAL) {
- // width -= (int)V2D_SCROLL_WIDTH;
- // }
- // if (scroll & V2D_SCROLL_VERTICAL) {
- // height -= (int)V2D_SCROLL_HEIGHT;
- // }
-
if (ELEM(0, width, height)) {
if (G.debug & G_DEBUG) {
printf("Error: View2D totRect set exiting: v2d=%p width=%d height=%d\n",
@@ -1047,20 +1031,12 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resiz
}
/* make sure that 'cur' rect is in a valid state as a result of these changes */
- ui_view2d_curRect_validate_resize(v2d, resize, 1);
+ ui_view2d_curRect_validate_resize(v2d, resize);
}
void UI_view2d_totRect_set(View2D *v2d, int width, int height)
{
- int scroll = view2d_scroll_mapped(v2d->scroll);
-
- UI_view2d_totRect_set_resize(v2d, width, height, 0);
-
- /* solve bad recursion... if scroller state changed,
- * mask is different, so you get different rects */
- if (scroll != view2d_scroll_mapped(v2d->scroll)) {
- UI_view2d_totRect_set_resize(v2d, width, height, 0);
- }
+ UI_view2d_totRect_set_resize(v2d, width, height, false);
}
bool UI_view2d_tab_set(View2D *v2d, int tab)
@@ -1258,7 +1234,7 @@ void UI_view2d_view_restore(const bContext *C)
* \{ */
/* Draw a constant grid in given 2d-region */
-void UI_view2d_constant_grid_draw(View2D *v2d, float step)
+void UI_view2d_constant_grid_draw(const View2D *v2d, float step)
{
float start_x, start_y;
int count_x, count_y;
@@ -1330,7 +1306,8 @@ void UI_view2d_constant_grid_draw(View2D *v2d, float step)
}
/* Draw a multi-level grid in given 2d-region */
-void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_size, int totlevels)
+void UI_view2d_multi_grid_draw(
+ const View2D *v2d, int colorid, float step, int level_size, int totlevels)
{
/* Exit if there is nothing to draw */
if (totlevels == 0) {
@@ -1448,7 +1425,7 @@ View2DScrollers *UI_view2d_scrollers_calc(View2D *v2d, const rcti *mask_custom)
scrollers = MEM_callocN(sizeof(View2DScrollers), "View2DScrollers");
/* Always update before drawing (for dynamically sized scrollers). */
- view2d_masks(v2d, false, mask_custom);
+ view2d_masks(v2d, mask_custom);
vert = v2d->vert;
hor = v2d->hor;
@@ -1801,7 +1778,8 @@ bool UI_view2d_view_to_region_clip(
* \param x, y: Coordinates to convert.
* \param r_region_x, r_region_y: Resultant coordinates.
*/
-void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
+void UI_view2d_view_to_region(
+ const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
/* step 1: express given coordinates as proportional values */
x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur);
@@ -1817,7 +1795,7 @@ void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, in
}
void UI_view2d_view_to_region_fl(
- View2D *v2d, float x, float y, float *r_region_x, float *r_region_y)
+ const View2D *v2d, float x, float y, float *r_region_x, float *r_region_y)
{
/* express given coordinates as proportional values */
x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur);
@@ -1828,7 +1806,7 @@ void UI_view2d_view_to_region_fl(
*r_region_y = v2d->mask.ymin + (y * BLI_rcti_size_y(&v2d->mask));
}
-void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect_dst)
+void UI_view2d_view_to_region_rcti(const View2D *v2d, const rctf *rect_src, rcti *rect_dst)
{
const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)};
const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)};
@@ -1849,7 +1827,7 @@ void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect
clamp_rctf_to_rcti(rect_dst, &rect_tmp);
}
-void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4])
+void UI_view2d_view_to_region_m4(const View2D *v2d, float matrix[4][4])
{
rctf mask;
unit_m4(matrix);
@@ -1857,7 +1835,7 @@ void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4])
BLI_rctf_transform_calc_m4_pivot_min(&v2d->cur, &mask, matrix);
}
-bool UI_view2d_view_to_region_rcti_clip(View2D *v2d, const rctf *rect_src, rcti *rect_dst)
+bool UI_view2d_view_to_region_rcti_clip(const View2D *v2d, const rctf *rect_src, rcti *rect_dst)
{
const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)};
const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)};
@@ -1983,7 +1961,7 @@ float UI_view2d_scale_get_y(const View2D *v2d)
/**
* Same as ``UI_view2d_scale_get() - 1.0f / x, y``
*/
-void UI_view2d_scale_get_inverse(View2D *v2d, float *r_x, float *r_y)
+void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
*r_x = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
@@ -1997,7 +1975,7 @@ void UI_view2d_scale_get_inverse(View2D *v2d, float *r_x, float *r_y)
* Simple functions for consistent center offset access.
* Used by node editor to shift view center for each individual node tree.
*/
-void UI_view2d_center_get(struct View2D *v2d, float *r_x, float *r_y)
+void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y)
{
/* get center */
if (r_x) {
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index a6dece91eb0..416c1dc6e49 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -521,8 +521,8 @@ void MASK_OT_select_box(wmOperatorType *ot)
* \{ */
static bool do_lasso_select_mask(bContext *C,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ short mcoords_len,
const eSelectOp sel_op)
{
ScrArea *area = CTX_wm_area(C);
@@ -540,7 +540,7 @@ static bool do_lasso_select_mask(bContext *C,
}
/* get rectangle from operator */
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* do actual selection */
LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
@@ -573,7 +573,7 @@ static bool do_lasso_select_mask(bContext *C,
&screen_co[1]);
if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) {
+ BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) {
BKE_mask_point_select_set(point, select);
BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, select);
changed = true;
@@ -594,14 +594,14 @@ static bool do_lasso_select_mask(bContext *C,
static int clip_lasso_select_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- do_lasso_select_mask(C, mcords, mcords_tot, sel_op);
+ do_lasso_select_mask(C, mcoords, mcoords_len, sel_op);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 23f622ac359..bf6c5a2f829 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -226,6 +226,7 @@ static bool edbm_extrude_ex(Object *obedit,
char htype,
const char hflag,
const bool use_normal_flip,
+ const bool use_dissolve_ortho_edges,
const bool use_mirror,
const bool use_select_history)
{
@@ -241,6 +242,7 @@ static bool edbm_extrude_ex(Object *obedit,
BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region");
BMO_slot_bool_set(extop.slots_in, "use_normal_flip", use_normal_flip);
+ BMO_slot_bool_set(extop.slots_in, "use_dissolve_ortho_edges", use_dissolve_ortho_edges);
BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history);
BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", htype, hflag);
@@ -312,7 +314,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
mul_v3_m3v3(offset_local, tmat, offset);
for (int a = 0; a < steps; a++) {
- edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, true);
+ edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false, true);
BMO_op_callf(
em->bm, BMO_FLAG_DEFAULTS, "translate vec=%v verts=%hv", offset_local, BM_ELEM_SELECT);
}
@@ -359,6 +361,7 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
{
const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip");
+ const bool use_dissolve_ortho_edges = RNA_boolean_get(op->ptr, "use_dissolve_ortho_edges");
const char htype = edbm_extrude_htype_from_em_select(em);
enum { NONE = 0, ELEM_FLAG, VERT_ONLY, EDGE_ONLY } nr;
bool changed = false;
@@ -401,7 +404,14 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
case NONE:
return false;
case ELEM_FLAG:
- changed = edbm_extrude_ex(obedit, em, htype, BM_ELEM_SELECT, use_normal_flip, true, true);
+ changed = edbm_extrude_ex(obedit,
+ em,
+ htype,
+ BM_ELEM_SELECT,
+ use_normal_flip,
+ use_dissolve_ortho_edges,
+ true,
+ true);
break;
case VERT_ONLY:
changed = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
@@ -465,6 +475,7 @@ void MESH_OT_extrude_region(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", "");
+ RNA_def_boolean(ot->srna, "use_dissolve_ortho_edges", false, "Dissolve Orthogonal Edges", "");
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
}
@@ -519,6 +530,7 @@ void MESH_OT_extrude_context(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", "");
+ RNA_def_boolean(ot->srna, "use_dissolve_ortho_edges", false, "Dissolve Orthogonal Edges", "");
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
}
@@ -840,7 +852,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
}
}
- edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, true, true);
+ edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, false, true, true);
EDBM_op_callf(
vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, local_center, mat);
EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v", BM_ELEM_SELECT, ofs);
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 48ec41027ff..e4ecfa9c680 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -397,9 +397,7 @@ struct UMArrayData {
UndoMesh *um;
const UndoMesh *um_ref; /* can be NULL */
};
-static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
struct UMArrayData *um_data = taskdata;
um_arraystore_compact_with_info(um_data->um, um_data->um_ref);
@@ -541,9 +539,7 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key)
# ifdef USE_ARRAY_STORE_THREAD
if (um_arraystore.task_pool == NULL) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- um_arraystore.task_pool = BLI_task_pool_create_background(
- scheduler, NULL, TASK_PRIORITY_LOW);
+ um_arraystore.task_pool = BLI_task_pool_create_background(NULL, TASK_PRIORITY_LOW);
}
struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 66b2c66f2aa..c52a5956ac4 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -277,6 +277,18 @@ void ED_operatormacros_mesh(void)
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
+ ot = WM_operatortype_append_macro(
+ "MESH_OT_extrude_region_dissolve_move_intersect",
+ "Extrude, Dissolve, Move and Intersect",
+ "Extrude, dissolves edges whose faces form a flat surface and intersect new edges",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region");
+ RNA_boolean_set(otmacro->ptr, "use_dissolve_ortho_edges", true);
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+ RNA_boolean_set(otmacro->ptr, "use_automerge_and_split", true);
+
ot = WM_operatortype_append_macro("MESH_OT_extrude_context_move",
"Extrude Region and Move",
"Extrude region together along the average normal",
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index c2c25e47908..fb273cf49a8 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -17,8 +17,8 @@
set(INC
../include
- ../../blenkernel
../../blenfont
+ ../../blenkernel
../../blenlib
../../blentranslation
../../bmesh
@@ -34,6 +34,7 @@ set(INC
../../shader_fx
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 5506895613b..d944d4c4dd3 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -100,6 +100,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "CLG_log.h"
+
/* for menu/popup icons etc etc*/
#include "UI_interface.h"
@@ -112,21 +114,17 @@
#include "object_intern.h" // own include
+static CLG_LogRef LOG = {"ed.object.edit"};
+
/* prototypes */
typedef struct MoveToCollectionData MoveToCollectionData;
static void move_to_collection_menus_items(struct uiLayout *layout,
struct MoveToCollectionData *menu);
static ListBase selected_objects_get(bContext *C);
-/* ************* XXX **************** */
-static void error(const char *UNUSED(arg))
-{
-}
-
-/* port over here */
-static void error_libdata(void)
-{
-}
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
Object *ED_object_context(bContext *C)
{
@@ -147,7 +145,11 @@ Object *ED_object_active_context(bContext *C)
return ob;
}
-/* ********************** object hiding *************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Operator
+ * \{ */
static bool object_hide_poll(bContext *C)
{
@@ -401,7 +403,11 @@ void OBJECT_OT_hide_collection(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
-/* ******************* toggle editmode operator ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Edit-Mode Operator
+ * \{ */
static bool mesh_needs_keyindex(Main *bmain, const Mesh *me)
{
@@ -441,7 +447,11 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
}
if (me->edit_mesh->bm->totvert > MESH_MAX_VERTS) {
- error("Too many vertices");
+ /* This used to be warned int the UI, we could warn again although it's quite rare. */
+ CLOG_WARN(&LOG,
+ "Too many vertices for mesh '%s' (%d)",
+ me->id.name + 2,
+ me->edit_mesh->bm->totvert);
return false;
}
@@ -600,7 +610,8 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag
}
if (BKE_object_obdata_is_libdata(ob)) {
- error_libdata();
+ /* Ideally the caller should check this. */
+ CLOG_WARN(&LOG, "Unable to enter edit-mode on library data for object '%s'", ob->id.name + 2);
return false;
}
@@ -777,7 +788,11 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* *************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Pose-Mode Operator
+ * \{ */
static int posemode_exec(bContext *C, wmOperator *op)
{
@@ -861,7 +876,11 @@ void OBJECT_OT_posemode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* force field toggle operator ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Force Field Toggle Operator
+ * \{ */
void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object)
{
@@ -924,8 +943,11 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************************************** */
-/* Motion Paths */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Calculate Motion Paths Operator
+ * \{ */
static eAnimvizCalcRange object_path_convert_range(eObjectPathCalcRange range)
{
@@ -1019,7 +1041,7 @@ static int object_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEv
}
/* show popup dialog to allow editing of range... */
- /* FIXME: hardcoded dimensions here are just arbitrary */
+ /* FIXME: hard-coded dimensions here are just arbitrary. */
return WM_operator_props_dialog_popup(C, op, 200);
}
@@ -1088,7 +1110,11 @@ void OBJECT_OT_paths_calculate(wmOperatorType *ot)
MAXFRAME / 2.0);
}
-/* --------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update Motion Paths Operator
+ * \{ */
static bool object_update_paths_poll(bContext *C)
{
@@ -1132,7 +1158,11 @@ void OBJECT_OT_paths_update(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* --------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Motion Paths Operator
+ * \{ */
/* Helper for ED_objects_clear_paths() */
static void object_clear_mpath(Object *ob)
@@ -1151,14 +1181,14 @@ static void object_clear_mpath(Object *ob)
void ED_objects_clear_paths(bContext *C, bool only_selected)
{
if (only_selected) {
- /* loop over all selected + sedtiable objects in scene */
+ /* Loop over all selected + editable objects in scene. */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
object_clear_mpath(ob);
}
CTX_DATA_END;
}
else {
- /* loop over all edtiable objects in scene */
+ /* Loop over all editable objects in scene. */
CTX_DATA_BEGIN (C, Object *, ob, editable_objects) {
object_clear_mpath(ob);
}
@@ -1210,13 +1240,17 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
-/* --------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update Motion Paths Range from Scene Operator
+ * \{ */
static int object_update_paths_range_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- /* loop over all edtiable objects in scene */
+ /* Loop over all editable objects in scene. */
CTX_DATA_BEGIN (C, Object *, ob, editable_objects) {
/* use Preview Range or Full Frame Range - whichever is in use */
ob->avs.path_sf = PSFRA;
@@ -1246,63 +1280,99 @@ void OBJECT_OT_paths_range_update(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** Smooth/Flat *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Shade Smooth/Flat Operator
+ * \{ */
static int shade_smooth_exec(bContext *C, wmOperator *op)
{
- ID *data;
- Curve *cu;
- Nurb *nu;
- int clear = (STREQ(op->idname, "OBJECT_OT_shade_flat"));
- bool done = false, linked_data = false;
+ const bool use_smooth = STREQ(op->idname, "OBJECT_OT_shade_smooth");
+ bool changed_multi = false;
+ bool has_linked_data = false;
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- data = ob->data;
+ ListBase ctx_objects = {NULL, NULL};
+ CollectionPointerLink ctx_ob_single_active = {NULL};
+
+ /* For modes that only use an active object, don't handle the whole selection. */
+ {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = OBACT(view_layer);
+ if (obact && ((obact->mode & OB_MODE_ALL_PAINT))) {
+ ctx_ob_single_active.ptr.data = obact;
+ BLI_addtail(&ctx_objects, &ctx_ob_single_active);
+ }
+ }
+
+ if (ctx_objects.first != &ctx_ob_single_active) {
+ CTX_data_selected_editable_objects(C, &ctx_objects);
+ }
+
+ for (CollectionPointerLink *ctx_ob = ctx_objects.first; ctx_ob; ctx_ob = ctx_ob->next) {
+ Object *ob = ctx_ob->ptr.data;
+ ID *data = ob->data;
+ if (data != NULL) {
+ data->tag |= LIB_TAG_DOIT;
+ }
+ }
+
+ for (CollectionPointerLink *ctx_ob = ctx_objects.first; ctx_ob; ctx_ob = ctx_ob->next) {
+ /* Always un-tag all object data-blocks irrespective of our ability to operate on them. */
+ Object *ob = ctx_ob->ptr.data;
+ ID *data = ob->data;
+ if ((data == NULL) || ((data->tag & LIB_TAG_DOIT) == 0)) {
+ continue;
+ }
+ data->tag &= ~LIB_TAG_DOIT;
+ /* Finished un-tagging, continue with regular logic. */
if (data && ID_IS_LINKED(data)) {
- linked_data = true;
+ has_linked_data = true;
continue;
}
+ bool changed = false;
if (ob->type == OB_MESH) {
- BKE_mesh_smooth_flag_set(ob->data, !clear);
-
+ BKE_mesh_smooth_flag_set(ob->data, use_smooth);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- done = true;
+ changed = true;
}
else if (ELEM(ob->type, OB_SURF, OB_CURVE)) {
- cu = ob->data;
+ BKE_curve_smooth_flag_set(ob->data, use_smooth);
+ changed = true;
+ }
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (!clear) {
- nu->flag |= ME_SMOOTH;
- }
- else {
- nu->flag &= ~ME_SMOOTH;
- }
- }
+ if (changed) {
+ changed_multi = true;
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- done = true;
}
}
- CTX_DATA_END;
- if (linked_data) {
+ if (ctx_objects.first != &ctx_ob_single_active) {
+ BLI_freelistN(&ctx_objects);
+ }
+
+ if (has_linked_data) {
BKE_report(op->reports, RPT_WARNING, "Can't edit linked mesh or curve data");
}
- return (done) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ return (changed_multi) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static bool shade_poll(bContext *C)
{
- return (CTX_data_edit_object(C) == NULL);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = OBACT(view_layer);
+ if (obact != NULL) {
+ /* Doesn't handle edit-data, sculpt dynamic-topology, or their undo systems. */
+ if (obact->mode & (OB_MODE_EDIT | OB_MODE_SCULPT)) {
+ return false;
+ }
+ }
+ return true;
}
void OBJECT_OT_shade_flat(wmOperatorType *ot)
@@ -1335,7 +1405,11 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Mode Set Operator
+ * \{ */
static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
PointerRNA *UNUSED(ptr),
@@ -1516,6 +1590,12 @@ void OBJECT_OT_mode_set_with_submode(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Link/Move to Collection Operator
+ * \{ */
+
static ListBase selected_objects_get(bContext *C)
{
ListBase objects = {NULL};
@@ -1856,3 +1936,5 @@ void OBJECT_OT_link_to_collection(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
ot->prop = prop;
}
+
+/** \} */
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index d8ba270073e..d7a7b4ca110 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -169,6 +169,8 @@ void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot);
void OBJECT_OT_multires_reshape(struct wmOperatorType *ot);
void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot);
+void OBJECT_OT_multires_unsubdivide(struct wmOperatorType *ot);
+void OBJECT_OT_multires_rebuild_subdiv(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index a24f3ba2269..bcc5bf3e1ae 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -142,10 +142,11 @@ static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph,
md_eval->mode = mode;
}
-/** Add a modifier to given object, including relevant extra processing needed by some physics
- * types (particles, simulations...).
+/**
+ * Add a modifier to given object, including relevant extra processing needed by some physics types
+ * (particles, simulations...).
*
- * \param scene is only used to set current frame in some cases, and may be NULL.
+ * \param scene: is only used to set current frame in some cases, and may be NULL.
*/
ModifierData *ED_object_modifier_add(
ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
@@ -1432,6 +1433,25 @@ void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot)
/** \name Multires Subdivide Operator
* \{ */
+static EnumPropertyItem prop_multires_subdivide_mode_type[] = {
+ {MULTIRES_SUBDIVIDE_CATMULL_CLARK,
+ "CATMULL_CLARK",
+ 0,
+ "Catmull-Clark",
+ "Create a new level using Catmull-Clark subdivisions"},
+ {MULTIRES_SUBDIVIDE_SIMPLE,
+ "SIMPLE",
+ 0,
+ "Simple",
+ "Create a new level using simple subdivisions"},
+ {MULTIRES_SUBDIVIDE_LINEAR,
+ "LINEAR",
+ 0,
+ "Linear",
+ "Create a new level using linear interpolation of the sculpted displacement"},
+ {0, NULL, 0, NULL, NULL},
+};
+
static int multires_subdivide_exec(bContext *C, wmOperator *op)
{
Object *object = ED_object_active_context(C);
@@ -1442,7 +1462,9 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- multiresModifier_subdivide(object, mmd);
+ const eMultiresSubdivideModeType subdivide_mode = (eMultiresSubdivideModeType)(
+ RNA_enum_get(op->ptr, "mode"));
+ multiresModifier_subdivide(object, mmd, subdivide_mode);
ED_object_iter_other(
CTX_data_main(C), object, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl);
@@ -1481,6 +1503,12 @@ void OBJECT_OT_multires_subdivide(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_multires_subdivide_mode_type,
+ MULTIRES_SUBDIVIDE_CATMULL_CLARK,
+ "Subdivision Mode",
+ "How the mesh is going to be subdivided to create a new level");
}
/** \} */
@@ -1738,6 +1766,119 @@ void OBJECT_OT_multires_base_apply(wmOperatorType *ot)
/** \} */
/* ------------------------------------------------------------------- */
+/** \name Multires Unsubdivide
+ * \{ */
+
+static int multires_unsubdivide_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *object = ED_object_active_context(C);
+ MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(
+ op, object, eModifierType_Multires);
+
+ if (!mmd) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true);
+ if (new_levels == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild a lower level");
+ return OPERATOR_CANCELLED;
+ }
+
+ DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
+
+ return OPERATOR_FINISHED;
+}
+
+static int multires_unsubdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op)) {
+ return multires_unsubdivide_exec(C, op);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_multires_unsubdivide(wmOperatorType *ot)
+{
+ ot->name = "Unsubdivide";
+ ot->description = "Rebuild a lower subdivision level of the current base mesh";
+ ot->idname = "OBJECT_OT_multires_unsubdivide";
+
+ ot->poll = multires_poll;
+ ot->invoke = multires_unsubdivide_invoke;
+ ot->exec = multires_unsubdivide_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
+
+/** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Multires Rebuild Subdivisions
+ * \{ */
+
+static int multires_rebuild_subdiv_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *object = ED_object_active_context(C);
+ MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(
+ op, object, eModifierType_Multires);
+
+ if (!mmd) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, INT_MAX, false);
+ if (new_levels == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild lower levels");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_reportf(op->reports, RPT_INFO, "%d new levels rebuilt", new_levels);
+
+ DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
+
+ return OPERATOR_FINISHED;
+}
+
+static int multires_rebuild_subdiv_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op)) {
+ return multires_rebuild_subdiv_exec(C, op);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_multires_rebuild_subdiv(wmOperatorType *ot)
+{
+ ot->name = "Rebuild Lower Subdivisions";
+ ot->description =
+ "Rebuilds all possible subdivisions levels to generate a lower resolution base mesh";
+ ot->idname = "OBJECT_OT_multires_rebuild_subdiv";
+
+ ot->poll = multires_poll;
+ ot->invoke = multires_rebuild_subdiv_invoke;
+ ot->exec = multires_rebuild_subdiv_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
+
+/** \} */
+
+/* ------------------------------------------------------------------- */
/** \name Skin Modifier
* \{ */
@@ -2455,7 +2596,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
* No drivers or other modifier parameters. */
/* TODO(sergey): This operates on an original data, so no flush is needed. However, baking
* usually should happen on an evaluated objects, so this seems to be deeper issue here. */
- BKE_animsys_evaluate_animdata(scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata((ID *)ob, ob->adt, f, ADT_RECALC_ANIM, false);
och->time[i] = omd->time;
i++;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index fef046169a7..819b6c18a44 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -137,6 +137,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_multires_reshape);
WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete);
WM_operatortype_append(OBJECT_OT_multires_base_apply);
+ WM_operatortype_append(OBJECT_OT_multires_unsubdivide);
+ WM_operatortype_append(OBJECT_OT_multires_rebuild_subdiv);
WM_operatortype_append(OBJECT_OT_multires_external_save);
WM_operatortype_append(OBJECT_OT_multires_external_pack);
WM_operatortype_append(OBJECT_OT_skin_root_mark);
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 62a8b46e904..132b530455e 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1608,6 +1608,7 @@ struct XFormAxisItem {
float rot_mat[3][3];
void *obtfm;
float xform_dist;
+ bool is_z_flip;
#ifdef USE_RELATIVE_ROTATION
/* use when translating multiple */
@@ -1730,11 +1731,16 @@ static void object_apply_location(Object *ob, const float loc[3])
static bool object_orient_to_location(Object *ob,
const float rot_orig[3][3],
const float axis[3],
- const float location[3])
+ const float location[3],
+ const bool z_flip)
{
float delta[3];
sub_v3_v3v3(delta, ob->obmat[3], location);
if (normalize_v3(delta) != 0.0f) {
+ if (z_flip) {
+ negate_v3(delta);
+ }
+
if (len_squared_v3v3(delta, axis) > FLT_EPSILON) {
float delta_rot[3][3];
float final_rot[3][3];
@@ -1841,6 +1847,11 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons
for (int i = 0; i < xfd->object_data_len; i++, item++) {
item->obtfm = BKE_object_tfm_backup(item->ob);
BKE_object_rot_to_mat3(item->ob, item->rot_mat, true);
+
+ /* Detect negative scale matrix. */
+ float full_mat3[3][3];
+ BKE_object_to_mat3(item->ob, full_mat3);
+ item->is_z_flip = dot_v3v3(item->rot_mat[2], full_mat3[2]) < 0.0f;
}
}
@@ -1975,7 +1986,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
}
object_orient_to_location(
- item->ob, item->rot_mat, item->rot_mat[2], location_world);
+ item->ob, item->rot_mat, item->rot_mat[2], location_world, item->is_z_flip);
DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
@@ -1989,8 +2000,11 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
else {
struct XFormAxisItem *item = xfd->object_data;
for (int i = 0; i < xfd->object_data_len; i++, item++) {
- if (object_orient_to_location(
- item->ob, item->rot_mat, item->rot_mat[2], location_world)) {
+ if (object_orient_to_location(item->ob,
+ item->rot_mat,
+ item->rot_mat[2],
+ location_world,
+ item->is_z_flip)) {
DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
}
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 75ae0299318..604f66002c2 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -849,7 +849,6 @@ static void foreach_mouse_hit_key(PEData *data, ForHitKeyMatFunc func, int selec
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, foreach_mouse_hit_key_iter, &settings);
}
@@ -1229,7 +1228,6 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, deflect_emitter_iter, &settings);
}
@@ -1278,7 +1276,6 @@ static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, apply_lengths_iter, &settings);
}
@@ -1353,7 +1350,6 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
}
@@ -2256,7 +2252,7 @@ bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float ra
/************************ lasso select operator ************************/
-int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op)
+int PE_lasso_select(bContext *C, const int mcoords[][2], const short mcoords_len, const int sel_op)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
@@ -2300,7 +2296,8 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const
const bool is_inside =
((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) ==
V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) &&
key_test_depth(&data, co, screen_co));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
@@ -2319,7 +2316,8 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const
const bool is_inside =
((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) ==
V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) &&
key_test_depth(&data, co, screen_co));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
@@ -4084,7 +4082,6 @@ typedef struct BrushAddCountIterData {
short size;
float imat[4][4];
ParticleData *add_pars;
- int num_added;
} BrushAddCountIterData;
typedef struct BrushAddCountIterTLSData {
@@ -4113,7 +4110,7 @@ static void brush_add_count_iter(void *__restrict iter_data_v,
dmy = size;
if (tls->rng == NULL) {
tls->rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1] +
- tls_v->thread_id);
+ BLI_task_parallel_thread_id(tls_v));
}
/* rejection sampling to get points in circle */
while (dmx * dmx + dmy * dmy > size2) {
@@ -4176,12 +4173,19 @@ static void brush_add_count_iter(void *__restrict iter_data_v,
}
}
-static void brush_add_count_iter_finalize(void *__restrict userdata_v,
- void *__restrict userdata_chunk_v)
+static void brush_add_count_iter_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict join_v,
+ void *__restrict chunk_v)
+{
+ BrushAddCountIterTLSData *join = (BrushAddCountIterTLSData *)join_v;
+ BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)chunk_v;
+ join->num_added += tls->num_added;
+}
+
+static void brush_add_count_iter_free(const void *__restrict UNUSED(userdata_v),
+ void *__restrict chunk_v)
{
- BrushAddCountIterData *iter_data = (BrushAddCountIterData *)userdata_v;
- BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)userdata_chunk_v;
- iter_data->num_added += tls->num_added;
+ BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)chunk_v;
if (tls->rng != NULL) {
BLI_rng_free(tls->rng);
}
@@ -4245,23 +4249,22 @@ static int brush_add(const bContext *C, PEData *data, short number)
iter_data.number = number;
iter_data.size = size;
iter_data.add_pars = add_pars;
- iter_data.num_added = 0;
copy_m4_m4(iter_data.imat, imat);
BrushAddCountIterTLSData tls = {NULL};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
settings.userdata_chunk = &tls;
settings.userdata_chunk_size = sizeof(BrushAddCountIterTLSData);
- settings.func_finalize = brush_add_count_iter_finalize;
+ settings.func_reduce = brush_add_count_iter_reduce;
+ settings.func_free = brush_add_count_iter_free;
BLI_task_parallel_range(0, number, &iter_data, brush_add_count_iter, &settings);
/* Convert add_parse to a dense array, where all new particles are in the
* beginning of the array.
*/
- n = iter_data.num_added;
+ n = tls.num_added;
for (int current_iter = 0, new_index = 0; current_iter < number; current_iter++) {
if (add_pars[current_iter].num == DMCACHE_NOTFOUND) {
continue;
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index eb808398254..5550f1a63c8 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -361,7 +361,7 @@ static void fluid_bake_endjob(void *customdata)
RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
}
else {
- if (mds->error != NULL && mds->error[0] != '\0') {
+ if (mds->error[0] != '\0') {
WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
else { /* User canceled the bake */
@@ -473,7 +473,7 @@ static void fluid_free_endjob(void *customdata)
RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
}
else {
- if (mds->error != NULL && mds->error[0] != '\0') {
+ if (mds->error[0] != '\0') {
WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
else { /* User canceled the free job */
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index f35f92feaec..f2e8209b099 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -144,7 +144,6 @@ typedef struct OGLRender {
wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
void **movie_ctx_arr;
- TaskScheduler *task_scheduler;
TaskPool *task_pool;
bool pool_ok;
bool is_animation;
@@ -630,6 +629,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
case ID_HA: /* Hair */
case ID_PT: /* PointCloud */
case ID_VO: /* Volume */
+ case ID_SIM: /* Simulation */
break;
/* Blacklist: */
@@ -855,22 +855,16 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
gather_frames_to_render(C, oglrender);
}
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- task_scheduler = BLI_task_scheduler_create(1);
- oglrender->task_scheduler = task_scheduler;
- oglrender->task_pool = BLI_task_pool_create_background(
- task_scheduler, oglrender, TASK_PRIORITY_LOW);
+ oglrender->task_pool = BLI_task_pool_create_background_serial(oglrender, TASK_PRIORITY_LOW);
}
else {
- oglrender->task_scheduler = NULL;
- oglrender->task_pool = BLI_task_pool_create(task_scheduler, oglrender, TASK_PRIORITY_LOW);
+ oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_LOW);
}
oglrender->pool_ok = true;
BLI_spin_init(&oglrender->reports_lock);
}
else {
- oglrender->task_scheduler = NULL;
oglrender->task_pool = NULL;
}
oglrender->num_scheduled_frames = 0;
@@ -909,10 +903,6 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
}
BLI_task_pool_work_and_wait(oglrender->task_pool);
BLI_task_pool_free(oglrender->task_pool);
- /* Depending on various things we might or might not use global scheduler. */
- if (oglrender->task_scheduler != NULL) {
- BLI_task_scheduler_free(oglrender->task_scheduler);
- }
BLI_spin_end(&oglrender->reports_lock);
}
BLI_mutex_end(&oglrender->task_mutex);
@@ -1032,9 +1022,9 @@ typedef struct WriteTaskData {
Scene tmp_scene;
} WriteTaskData;
-static void write_result_func(TaskPool *__restrict pool, void *task_data_v, int UNUSED(thread_id))
+static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
{
- OGLRender *oglrender = (OGLRender *)BLI_task_pool_userdata(pool);
+ OGLRender *oglrender = (OGLRender *)BLI_task_pool_user_data(pool);
WriteTaskData *task_data = (WriteTaskData *)task_data_v;
Scene *scene = &task_data->tmp_scene;
RenderResult *rr = task_data->rr;
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 49838b62b71..bbc6b9e7c86 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -2515,6 +2515,7 @@ void ED_region_panels_layout_ex(const bContext *C,
int margin_x = 0;
const bool region_layout_based = region->flag & RGN_FLAG_DYNAMIC_SIZE;
const bool is_context_new = (contextnr != -1) ? UI_view2d_tab_set(v2d, contextnr) : false;
+ bool update_tot_size = true;
/* before setting the view */
if (vertical) {
@@ -2532,7 +2533,6 @@ void ED_region_panels_layout_ex(const bContext *C,
v2d->scroll |= (V2D_SCROLL_BOTTOM);
v2d->scroll &= ~(V2D_SCROLL_RIGHT);
}
- const int scroll = v2d->scroll;
/* collect categories */
if (use_category_tabs) {
@@ -2584,6 +2584,11 @@ void ED_region_panels_layout_ex(const bContext *C,
}
}
+ if (panel && UI_panel_is_dragging(panel)) {
+ /* Prevent View2d.tot rectangle size changes while dragging panels. */
+ update_tot_size = false;
+ }
+
ed_panel_draw(C, area, region, &region->panels, pt, panel, w, em, vertical);
}
@@ -2639,17 +2644,9 @@ void ED_region_panels_layout_ex(const bContext *C,
y = -y;
}
- /* this also changes the 'cur' */
- UI_view2d_totRect_set(v2d, x, y);
-
- if (scroll != v2d->scroll) {
- /* Note: this code scales fine, but because of rounding differences, positions of elements
- * flip +1 or -1 pixel compared to redoing the entire layout again.
- * Leaving in commented code for future tests */
-#if 0
- UI_panels_scale(region, BLI_rctf_size_x(&v2d->cur));
- break;
-#endif
+ if (update_tot_size) {
+ /* this also changes the 'cur' */
+ UI_view2d_totRect_set(v2d, x, y);
}
if (use_category_tabs) {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 452984f2333..eccc15456ae 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -3870,7 +3870,6 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
rv3d->viewlock_quad = RV3D_VIEWLOCK_INIT;
rv3d->viewlock = 0;
- rv3d->rflag &= ~RV3D_CLIPPING;
/* Accumulate locks, in case they're mixed. */
for (region_iter = area->regionbase.first; region_iter; region_iter = region_iter->next) {
@@ -4389,7 +4388,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
wmWindow *window;
ScrArea *area;
int sync;
- float time;
+ double time;
/* sync, don't sync, or follow scene setting */
if (sad->flag & ANIMPLAY_FLAG_SYNC) {
@@ -4412,7 +4411,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
else if ((scene->audio.flag & AUDIO_SYNC) && (sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
isfinite(time = BKE_sound_sync_scene(scene_eval))) {
- double newfra = (double)time * FPS;
+ double newfra = time * FPS;
/* give some space here to avoid jumps */
if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra) {
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 536453ad085..f6f84ad1229 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -171,6 +171,8 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
bool convert_to_linear = false;
struct ColorSpace *colorspace = NULL;
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
/* For consistency, sampling always returns color in linear space. */
@@ -214,8 +216,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
if (col) {
float rgba[4];
- paint_get_tex_pixel_col(
- mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace);
+ paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace);
buffer[index * 4] = rgba[0] * 255;
buffer[index * 4 + 1] = rgba[1] * 255;
@@ -223,7 +224,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
buffer[index * 4 + 3] = rgba[3] * 255;
}
else {
- float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id);
+ float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id);
avg += br->texture_sample_bias;
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 6af9ec01fc3..3dc6305dcf2 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -5168,9 +5168,7 @@ static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf)
}
/* Run this for single and multi-threaded painting. */
-static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool),
- void *ph_v,
- int UNUSED(threadid))
+static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v)
{
/* First unpack args from the struct */
ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps;
@@ -5605,7 +5603,6 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
bool touch_any = false;
ProjectHandle handles[BLENDER_MAX_THREADS];
- TaskScheduler *scheduler = NULL;
TaskPool *task_pool = NULL;
int a, i;
@@ -5616,8 +5613,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
}
if (ps->thread_tot > 1) {
- scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create_suspended(scheduler, NULL, TASK_PRIORITY_HIGH);
+ task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH);
}
image_pool = BKE_image_pool_new();
@@ -5661,7 +5657,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
BLI_task_pool_free(task_pool);
}
else {
- do_projectpaint_thread(NULL, &handles[0], 0);
+ do_projectpaint_thread(NULL, &handles[0]);
}
BKE_image_pool_free(image_pool);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index fb8cc3a639b..89cf090b7c6 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -168,9 +168,9 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
.value = value,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings);
if (multires) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
@@ -343,9 +343,9 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
.clip_planes_final = clip_planes_final,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
if (nodes) {
MEM_freeN(nodes);
@@ -456,10 +456,10 @@ static void mask_gesture_lasso_task_cb(void *__restrict userdata,
static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
float clip_planes[4][4], clip_planes_final[4][4];
BoundBox bb;
@@ -485,7 +485,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
ob = vc.obact;
ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat);
- BLI_lasso_boundbox(&data.rect, mcords, mcords_tot);
+ BLI_lasso_boundbox(&data.rect, mcoords, mcoords_len);
data.width = data.rect.xmax - data.rect.xmin;
data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__);
@@ -493,8 +493,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.rect.ymin,
data.rect.xmax,
data.rect.ymax,
- mcords,
- mcords_tot,
+ mcoords,
+ mcoords_len,
mask_lasso_px_cb,
&data);
@@ -532,9 +532,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.task_data.mode = mode;
data.task_data.value = value;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
if (nodes) {
MEM_freeN(nodes);
@@ -551,7 +551,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
SCULPT_undo_push_end();
ED_region_tag_redraw(vc.region);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
MEM_freeN(data.px);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 60b4a2f8e0c..c84a3b9cbfc 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -166,10 +166,11 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3], flo
float paint_get_tex_pixel(const MTex *mtex, float u, float v, struct ImagePool *pool, int thread)
{
- float intensity, rgba[4];
+ float intensity;
+ float rgba_dummy[4];
float co[3] = {u, v, 0.0f};
- externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba_dummy);
return intensity;
}
@@ -184,11 +185,10 @@ void paint_get_tex_pixel_col(const MTex *mtex,
struct ColorSpace *colorspace)
{
float co[3] = {u, v, 0.0f};
- int hasrgb;
float intensity;
- hasrgb = externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ const bool hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
+
if (!hasrgb) {
rgba[0] = intensity;
rgba[1] = intensity;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index d050a39ce68..5b9f1f600e6 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -2183,9 +2183,9 @@ static void calculate_average_weight(SculptThreadedTaskData *data,
struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
uint accum_len = 0;
double accum_weight = 0.0;
@@ -2231,22 +2231,22 @@ static void wpaint_paint_leaves(bContext *C,
data.strength = BKE_brush_weight_get(scene, brush);
/* NOTE: current mirroring code cannot be run in parallel */
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, !(me->editflag & ME_EDIT_MIRROR_X), totnode);
switch ((eBrushWeightPaintTool)brush->weightpaint_tool) {
case WPAINT_TOOL_AVERAGE:
calculate_average_weight(&data, nodes, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
break;
case WPAINT_TOOL_SMEAR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
break;
case WPAINT_TOOL_BLUR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
break;
case WPAINT_TOOL_DRAW:
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
break;
}
}
@@ -3252,9 +3252,9 @@ static void calculate_average_color(SculptThreadedTaskData *data,
struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
uint accum_len = 0;
uint accum_value[3] = {0};
@@ -3298,21 +3298,21 @@ static void vpaint_paint_leaves(bContext *C,
.lcol = (uint *)me->mloopcol,
.me = me,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
case VPAINT_TOOL_AVERAGE:
calculate_average_color(&data, nodes, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
break;
case VPAINT_TOOL_BLUR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
break;
case VPAINT_TOOL_SMEAR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
break;
case VPAINT_TOOL_DRAW:
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
break;
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 9b00feb1cf8..ce5433f680e 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -806,12 +806,12 @@ int SCULPT_nearest_vertex_get(
nvtd.nearest_vertex_index = -1;
nvtd.nearest_vertex_distance_squared = FLT_MAX;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
settings.func_reduce = nearest_vertex_get_reduce;
settings.userdata_chunk = &nvtd;
settings.userdata_chunk_size = sizeof(NearestVertexTLSData);
- BKE_pbvh_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
MEM_SAFE_FREE(nodes);
@@ -1283,9 +1283,9 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
MEM_SAFE_FREE(nodes);
}
@@ -1909,12 +1909,12 @@ static void calc_area_center(
AreaNormalCenterTLSData anctd = {{{0}}};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
settings.func_reduce = calc_area_normal_and_center_reduce;
settings.userdata_chunk = &anctd;
settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
- BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* For flatten center. */
for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) {
@@ -1968,12 +1968,12 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
AreaNormalCenterTLSData anctd = {{{0}}};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode);
settings.func_reduce = calc_area_normal_and_center_reduce;
settings.userdata_chunk = &anctd;
settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
- BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* For area normal. */
for (int i = 0; i < ARRAY_SIZE(anctd.area_nos); i++) {
@@ -2009,12 +2009,12 @@ static void calc_area_normal_and_center(
AreaNormalCenterTLSData anctd = {{{0}}};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
settings.func_reduce = calc_area_normal_and_center_reduce;
settings.userdata_chunk = &anctd;
settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
- BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* For flatten center. */
for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) {
@@ -2100,7 +2100,7 @@ static float brush_strength(const Sculpt *sd,
return alpha * pressure * overlap * feather * 2.0f;
case SCULPT_TOOL_CLAY_STRIPS:
/* Clay Strips needs less strength to compensate the curve. */
- final_pressure = pressure * pressure * pressure;
+ final_pressure = powf(pressure, 1.5f);
return alpha * flip * final_pressure * overlap * feather * 0.3f;
case SCULPT_TOOL_CLAY_THUMB:
final_pressure = pressure * pressure;
@@ -2618,22 +2618,17 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength *
- SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- *vd.mask,
- vd.index,
- tls->thread_id) *
- ss->cache->pressure;
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
+ ss->cache->pressure;
float avg[3], val[3];
@@ -2675,10 +2670,10 @@ static void bmesh_topology_rake(
.nodes = nodes,
.strength = factor,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
}
}
@@ -2696,12 +2691,13 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
if (bstrength > 0.0f) {
(*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
@@ -2731,9 +2727,9 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
}
static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2768,6 +2764,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -2781,7 +2778,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -2818,9 +2815,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.offset = offset,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
}
static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
@@ -2843,6 +2840,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -2857,7 +2855,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -2894,9 +2892,9 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.offset = offset,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
}
/* -------------------------------------------------------------------- */
@@ -2923,6 +2921,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -2936,7 +2935,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float current_disp[3];
float current_disp_norm[3];
float final_disp[3];
@@ -3037,6 +3036,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3050,7 +3050,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
if (vd.mvert) {
@@ -3079,15 +3079,15 @@ static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
if (ss->cache->alt_smooth) {
for (int i = 0; i < 4; i++) {
- BKE_pbvh_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
}
}
else {
- BKE_pbvh_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
}
}
@@ -3200,6 +3200,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3213,7 +3214,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float val1[3];
float val2[3];
@@ -3288,9 +3289,9 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.flippedbstrength = flippedbstrength,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
}
static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
@@ -3311,6 +3312,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
float x_object_space[3];
float z_object_space[3];
@@ -3328,7 +3330,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float disp_center[3];
float x_disp[3];
float z_disp[3];
@@ -3401,9 +3403,9 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.stroke_xz = stroke_xz,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
}
static void do_grab_brush_task_cb_ex(void *__restrict userdata,
@@ -3427,6 +3429,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3441,7 +3444,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -3473,9 +3476,9 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
}
static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
@@ -3582,9 +3585,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
.grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
}
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3])
@@ -3744,6 +3747,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3756,7 +3760,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -3788,9 +3792,9 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
}
static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
@@ -3817,6 +3821,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3829,7 +3834,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -3909,9 +3914,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
}
static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
@@ -3935,6 +3940,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3949,7 +3955,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -3981,9 +3987,9 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
}
static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
@@ -4007,6 +4013,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4022,7 +4029,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
@@ -4054,9 +4061,9 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.angle = angle,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
}
static void do_layer_brush_task_cb_ex(void *__restrict userdata,
@@ -4078,6 +4085,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4092,7 +4100,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
const int vi = vd.index;
float *disp_factor;
@@ -4170,9 +4178,9 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
}
static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
@@ -4192,6 +4200,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4204,7 +4213,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float val[3];
if (vd.fno) {
@@ -4236,9 +4245,9 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
}
int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
@@ -4294,6 +4303,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
@@ -4316,7 +4326,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -4360,9 +4370,9 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
}
/* -------------------------------------------------------------------- */
@@ -4448,6 +4458,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
@@ -4468,7 +4479,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -4510,13 +4521,13 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
ClaySampleData csd = {{0}};
- PBVHParallelSettings sample_settings;
+ TaskParallelSettings sample_settings;
BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
sample_settings.func_reduce = calc_clay_surface_reduce;
sample_settings.userdata_chunk = &csd;
sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
- BKE_pbvh_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
+ BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
d_offset = min_ff(radius, d_offset);
@@ -4541,9 +4552,9 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
}
static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
@@ -4567,6 +4578,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
SCULPT_brush_test_init(ss, &test);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4590,7 +4602,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -4612,7 +4624,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
const bool flip = (ss->cache->bstrength < 0.0f);
const float radius = flip ? -ss->cache->radius : ss->cache->radius;
const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.25f + offset);
+ const float displace = radius * (0.18f + offset);
/* The sculpt-plane normal (whatever its set to). */
float area_no_sp[3];
@@ -4674,9 +4686,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
.mat = mat,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
}
static void do_fill_brush_task_cb_ex(void *__restrict userdata,
@@ -4698,6 +4710,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
@@ -4721,7 +4734,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -4767,9 +4780,9 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
}
static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
@@ -4791,6 +4804,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
@@ -4813,7 +4827,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -4859,9 +4873,9 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
}
/* -------------------------------------------------------------------- */
@@ -4889,6 +4903,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
float plane_tilt[4];
float normal_tilt[3];
@@ -4929,7 +4944,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5031,9 +5046,9 @@ static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.clay_strength = clay_strength,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
}
/** \} */
@@ -5055,6 +5070,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -5067,7 +5083,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -5102,9 +5118,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
.offset = offset,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
}
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
@@ -5294,9 +5310,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
/* Draw Face Sets in draw mode makes a single undo push, in alt-smooth mode deforms the
* vertices and uses regular coords undo. */
@@ -5557,9 +5573,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
}
MEM_SAFE_FREE(nodes);
@@ -5645,9 +5661,9 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
.vertCos = vertCos,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, SCULPT_flush_stroke_deform_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, SCULPT_flush_stroke_deform_task_cb, &settings);
if (vertCos) {
SCULPT_vertcos_to_key(ob, ss->shapekey_active, vertCos);
@@ -6173,7 +6189,7 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
case SCULPT_TOOL_CLAY:
return max_ff(initial_size * 0.20f, initial_size * pow3f(cache->pressure));
case SCULPT_TOOL_CLAY_STRIPS:
- return max_ff(initial_size * 0.30f, initial_size * pow2f(cache->pressure));
+ return max_ff(initial_size * 0.30f, initial_size * powf(cache->pressure, 1.5f));
case SCULPT_TOOL_CLAY_THUMB: {
float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache);
return initial_size * clay_stabilized_pressure;
@@ -7501,7 +7517,7 @@ static int ed_object_sculptmode_flush_recalc_flag(Scene *scene,
{
int flush_recalc = 0;
/* Multires in sculpt mode could have different from object mode subdivision level. */
- flush_recalc |= mmd && BKE_multires_sculpt_level_get(mmd) != mmd->lvl;
+ flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
/* If object has got active modifiers, it's dm could be different in sculpt mode. */
flush_recalc |= sculpt_has_active_modifiers(scene, ob);
return flush_recalc;
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index b1cc6d02bbb..215f4388715 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -221,6 +221,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
/* For Pich Perpendicular Deform Type. */
float x_object_space[3];
@@ -269,7 +270,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float brush_disp[3];
float normal[3];
@@ -412,7 +413,7 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd,
* storing the constraints per node. */
/* Currently all constrains are added to the same global array which can't be accessed from
* different threads. */
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, false, totnode);
SculptThreadedTaskData build_constraints_data = {
@@ -421,7 +422,7 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd,
.brush = brush,
.nodes = nodes,
};
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &build_constraints_data, do_cloth_brush_build_constraints_task_cb_ex, &settings);
}
@@ -490,9 +491,9 @@ static void cloth_brush_do_simulation_step(Sculpt *sd, Object *ob, PBVHNode **no
.cloth_time_step = CLOTH_SIMULATION_TIME_STEP,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &solve_simulation_data, do_cloth_brush_solve_simulation_task_cb_ex, &settings);
}
@@ -565,9 +566,9 @@ static void cloth_brush_apply_brush_foces(Sculpt *sd, Object *ob, PBVHNode **nod
}
}
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &apply_forces_data, do_cloth_brush_apply_forces_task_cb_ex, &settings);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index c8769523823..e58ffb2c9e6 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -87,6 +87,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -107,7 +108,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) {
ss->face_sets[vert_map->indices[j]] = abs(ss->cache->paint_face_set);
@@ -127,7 +128,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
if (fade > 0.05f) {
SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set);
@@ -160,6 +161,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
bstrength *= 2.0f;
}
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
@@ -172,7 +175,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
if (vd.mvert) {
@@ -211,15 +214,15 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
if (ss->cache->alt_smooth) {
for (int i = 0; i < 4; i++) {
- BKE_pbvh_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings);
}
}
else {
- BKE_pbvh_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index 38bbd083994..2d47eb3a9c8 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -246,9 +246,9 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
.prev_mask = prev_mask,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
MEM_freeN(prev_mask);
@@ -275,9 +275,9 @@ void SCULPT_mask_filter_smooth_apply(
};
for (int i = 0; i < smooth_iterations; i++) {
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
}
}
@@ -458,17 +458,17 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
.max = -FLT_MAX,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
settings.func_reduce = dirty_mask_compute_range_reduce;
settings.userdata_chunk = &range;
settings.userdata_chunk_size = sizeof(DirtyMaskRangeData);
- BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings);
data.dirty_mask_min = range.min;
data.dirty_mask_max = range.max;
- BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings);
MEM_SAFE_FREE(nodes);
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index 94b6e0eb864..f7b3bf32200 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -112,10 +112,10 @@ void SCULPT_filter_cache_init(Object *ob, Sculpt *sd)
.nodes = ss->filter_cache->nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(
&settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings);
}
@@ -496,13 +496,13 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *
.filter_strength = filter_strength,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(
&settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
if (filter_type == MESH_FILTER_SURFACE_SMOOTH) {
- BKE_pbvh_parallel_range(0,
+ BLI_task_parallel_range(0,
ss->filter_cache->totnode,
&data,
mesh_filter_surface_smooth_displace_task_cb,
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 34ca92acef9..2d71e4df076 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -288,10 +288,10 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
.mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
.mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"),
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(
&settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
ss->filter_cache->mask_update_current_it = mask_expand_update_it;
}
@@ -458,10 +458,10 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
.mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
.mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"),
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(
&settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
const char *status_str = TIP_(
"Move the mouse to expand the mask from the active vertex. LMB: confirm mask, ESC/RMB: "
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index c74a2ba503a..6ca696d4f65 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -79,6 +79,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
/* Apply the brush normal radius to the test before sampling. */
float test_radius = sqrtf(test.radius_squared);
@@ -107,7 +108,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
/* Sample the normal and area of the +X and -X axis individually. */
if (local_co[0] > 0.0f) {
@@ -163,6 +164,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -208,7 +210,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -301,13 +303,13 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes,
MultiplaneScrapeSampleData mssd = {{{0}}};
- PBVHParallelSettings sample_settings;
+ TaskParallelSettings sample_settings;
BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
sample_settings.func_reduce = calc_multiplane_scrape_surface_reduce;
sample_settings.userdata_chunk = &mssd;
sample_settings.userdata_chunk_size = sizeof(MultiplaneScrapeSampleData);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &sample_data, calc_multiplane_scrape_surface_task_cb, &sample_settings);
float sampled_plane_normals[2][3];
@@ -392,9 +394,9 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes,
normalize_v3(plane_no);
plane_from_point_normal_v3(data.multiplane_scrape_planes[0], area_co, plane_no);
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings);
}
void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr,
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index fde4a9d1d23..a90829741bf 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -263,7 +263,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd,
};
data.pose_initial_co = pose_target;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
PoseGrowFactorTLSData gftd;
gftd.pos_count = 0;
zero_v3(gftd.pos_avg);
@@ -279,7 +279,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd,
zero_v3(gftd.pos_avg);
gftd.pos_count = 0;
memcpy(data.prev_mask, pose_factor, SCULPT_vertex_count_get(ss) * sizeof(float));
- BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings);
if (gftd.pos_count != 0) {
mul_v3_fl(gftd.pos_avg, 1.0f / (float)gftd.pos_count);
@@ -793,9 +793,9 @@ void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br
for (int ik = 0; ik < ss->cache->pose_ik_chain->tot_segments; ik++) {
data.pose_factor = ss->cache->pose_ik_chain->segments[ik].weights;
for (int i = 0; i < br->pose_smooth_iterations; i++) {
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
}
}
@@ -885,9 +885,9 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
}
void SCULPT_pose_ik_chain_free(SculptPoseIKChain *ik_chain)
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 3a09d52d418..0b7057a2cb0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -245,6 +245,8 @@ static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata,
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
@@ -257,7 +259,7 @@ static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata,
vd.fno,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
vd.index,
- tls->thread_id);
+ thread_id);
if (smooth_mask) {
float val = SCULPT_neighbor_mask_average(ss, vd.vert_indices[vd.i]) - *vd.mask;
val *= fade * bstrength;
@@ -301,6 +303,7 @@ static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -313,7 +316,7 @@ static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata,
vd.fno,
smooth_mask ? 0.0f : *vd.mask,
vd.index,
- tls->thread_id);
+ thread_id);
if (smooth_mask) {
float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask;
val *= fade * bstrength;
@@ -358,6 +361,8 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
@@ -370,7 +375,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
vd.fno,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
vd.index,
- tls->thread_id);
+ thread_id);
if (smooth_mask) {
float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask;
val *= fade * bstrength;
@@ -427,18 +432,18 @@ void SCULPT_smooth(Sculpt *sd,
.strength = strength,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
switch (type) {
case PBVH_GRIDS:
- BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
break;
case PBVH_FACES:
- BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
break;
case PBVH_BMESH:
- BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
break;
}
}
@@ -512,6 +517,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
@@ -522,7 +528,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
const float fade =
bstrength *
SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
float disp[3];
SCULPT_surface_smooth_laplacian_step(ss,
@@ -555,6 +561,7 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -562,7 +569,7 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
const float fade =
bstrength *
SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
SCULPT_surface_smooth_displace_step(
ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade);
}
@@ -590,12 +597,12 @@ void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
for (int i = 0; i < brush->surface_smooth_iterations; i++) {
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &data, SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex, &settings);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &data, SCULPT_do_surface_smooth_brush_displace_task_cb_ex, &settings);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index c7cbb6672a4..cf46ca0097e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -177,10 +177,10 @@ void ED_sculpt_update_modal_transform(struct bContext *C)
mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]);
}
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(
&settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
if (ss->deform_modifiers_active || ss->shapekey_active) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 414a6101071..6c8b73723eb 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -415,9 +415,9 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings);
if (nodes) {
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 26c29d6cbe7..bbb68f632fb 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -793,8 +793,8 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
data_lasso.rectf_view = &rect_fl;
- data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
- if (data_lasso.mcords == NULL) {
+ data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcoords_len);
+ if (data_lasso.mcoords == NULL) {
return OPERATOR_CANCELLED;
}
@@ -805,13 +805,13 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
/* get settings from operator */
- BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_lasso_boundbox(&rect, data_lasso.mcoords, data_lasso.mcoords_len);
BLI_rctf_rcti_copy(&rect_fl, &rect);
/* apply box_select action */
region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
- MEM_freeN((void *)data_lasso.mcords);
+ MEM_freeN((void *)data_lasso.mcoords);
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index a1652ca0e88..fe7ae7096a0 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -1651,7 +1651,7 @@ static void draw_tracking_tracks(SpaceClip *sc,
pos[0] = (pos[0] / (pos[3] * 2.0f) + 0.5f) * width;
pos[1] = (pos[1] / (pos[3] * 2.0f) + 0.5f) * height * aspy;
- BKE_tracking_distort_v2(tracking, pos, npos);
+ BKE_tracking_distort_v2(tracking, width, height, pos, npos);
if (npos[0] >= 0.0f && npos[1] >= 0.0f && npos[0] <= width && npos[1] <= height * aspy) {
vec[0] = (marker->pos[0] + track->offset[0]) * width;
@@ -1730,8 +1730,7 @@ static void draw_distortion(SpaceClip *sc,
{
float x, y;
const int n = 10;
- int i, j, a;
- float pos[2], tpos[2], grid[11][11][2];
+ float tpos[2], grid[11][11][2];
MovieTracking *tracking = &clip->tracking;
bGPdata *gpd = NULL;
float aspy = 1.0f / tracking->camera.pixel_aspect;
@@ -1764,7 +1763,7 @@ static void draw_distortion(SpaceClip *sc,
float val[4][2], idx[4][2];
float min[2], max[2];
- for (a = 0; a < 4; a++) {
+ for (int a = 0; a < 4; a++) {
if (a < 2) {
val[a][a % 2] = FLT_MAX;
}
@@ -1773,13 +1772,13 @@ static void draw_distortion(SpaceClip *sc,
}
}
- zero_v2(pos);
- for (i = 0; i <= n; i++) {
- for (j = 0; j <= n; j++) {
+ for (int i = 0; i <= n; i++) {
+ for (int j = 0; j <= n; j++) {
if (i == 0 || j == 0 || i == n || j == n) {
- BKE_tracking_distort_v2(tracking, pos, tpos);
+ const float pos[2] = {dx * j, dy * i};
+ BKE_tracking_distort_v2(tracking, width, height, pos, tpos);
- for (a = 0; a < 4; a++) {
+ for (int a = 0; a < 4; a++) {
int ok;
if (a < 2) {
@@ -1796,59 +1795,49 @@ static void draw_distortion(SpaceClip *sc,
}
}
}
-
- pos[0] += dx;
}
-
- pos[0] = 0.0f;
- pos[1] += dy;
}
INIT_MINMAX2(min, max);
- for (a = 0; a < 4; a++) {
- pos[0] = idx[a][0] * dx;
- pos[1] = idx[a][1] * dy;
+ for (int a = 0; a < 4; a++) {
+ const float pos[2] = {idx[a][0] * dx, idx[a][1] * dy};
- BKE_tracking_undistort_v2(tracking, pos, tpos);
+ BKE_tracking_undistort_v2(tracking, width, height, pos, tpos);
minmax_v2v2_v2(min, max, tpos);
}
- copy_v2_v2(pos, min);
dx = (max[0] - min[0]) / n;
dy = (max[1] - min[1]) / n;
- for (i = 0; i <= n; i++) {
- for (j = 0; j <= n; j++) {
- BKE_tracking_distort_v2(tracking, pos, grid[i][j]);
+ for (int i = 0; i <= n; i++) {
+ for (int j = 0; j <= n; j++) {
+ const float pos[2] = {min[0] + dx * j, min[1] + dy * i};
+
+ BKE_tracking_distort_v2(tracking, width, height, pos, grid[i][j]);
grid[i][j][0] /= width;
grid[i][j][1] /= height * aspy;
-
- pos[0] += dx;
}
-
- pos[0] = min[0];
- pos[1] += dy;
}
immUniformColor3f(1.0f, 0.0f, 0.0f);
- for (i = 0; i <= n; i++) {
+ for (int i = 0; i <= n; i++) {
immBegin(GPU_PRIM_LINE_STRIP, n + 1);
- for (j = 0; j <= n; j++) {
+ for (int j = 0; j <= n; j++) {
immVertex2fv(position, grid[i][j]);
}
immEnd();
}
- for (j = 0; j <= n; j++) {
+ for (int j = 0; j <= n; j++) {
immBegin(GPU_PRIM_LINE_STRIP, n + 1);
- for (i = 0; i <= n; i++) {
+ for (int i = 0; i <= n; i++) {
immVertex2fv(position, grid[i][j]);
}
@@ -1882,8 +1871,8 @@ static void draw_distortion(SpaceClip *sc,
while (stroke) {
if (stroke->flag & GP_STROKE_2DSPACE) {
if (stroke->totpoints > 1) {
- for (i = 0; i < stroke->totpoints - 1; i++) {
- float npos[2], dpos[2], len;
+ for (int i = 0; i < stroke->totpoints - 1; i++) {
+ float pos[2], npos[2], dpos[2], len;
int steps;
pos[0] = (stroke->points[i].x + offsx) * width;
@@ -1897,8 +1886,8 @@ static void draw_distortion(SpaceClip *sc,
/* we want to distort only long straight lines */
if (stroke->totpoints == 2) {
- BKE_tracking_undistort_v2(tracking, pos, pos);
- BKE_tracking_undistort_v2(tracking, npos, npos);
+ BKE_tracking_undistort_v2(tracking, width, height, pos, pos);
+ BKE_tracking_undistort_v2(tracking, width, height, npos, npos);
}
sub_v2_v2v2(dpos, npos, pos);
@@ -1906,8 +1895,8 @@ static void draw_distortion(SpaceClip *sc,
immBegin(GPU_PRIM_LINE_STRIP, steps + 1);
- for (j = 0; j <= steps; j++) {
- BKE_tracking_distort_v2(tracking, pos, tpos);
+ for (int j = 0; j <= steps; j++) {
+ BKE_tracking_distort_v2(tracking, width, height, pos, tpos);
immVertex2f(position, tpos[0] / width, tpos[1] / (height * aspy));
add_v2_v2(pos, dpos);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index cce01947ab7..5be4b2d5df0 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -546,7 +546,7 @@ void ED_clip_point_undistorted_pos(SpaceClip *sc, const float co[2], float r_co[
r_co[0] *= width;
r_co[1] *= height * aspy;
- BKE_tracking_undistort_v2(&clip->tracking, r_co, r_co);
+ BKE_tracking_undistort_v2(&clip->tracking, width, height, r_co, r_co);
r_co[0] /= width;
r_co[1] /= height * aspy;
@@ -580,7 +580,7 @@ void ED_clip_point_stable_pos(
float aspy = 1.0f / tracking->camera.pixel_aspect;
float tmp[2] = {*xr * width, *yr * height * aspy};
- BKE_tracking_distort_v2(tracking, tmp, tmp);
+ BKE_tracking_distort_v2(tracking, width, height, tmp, tmp);
*xr = tmp[0] / width;
*yr = tmp[1] / (height * aspy);
@@ -885,9 +885,9 @@ static uchar *prefetch_thread_next_frame(PrefetchQueue *queue,
return mem;
}
-static void prefetch_task_func(TaskPool *__restrict pool, void *task_data, int UNUSED(threadid))
+static void prefetch_task_func(TaskPool *__restrict pool, void *task_data)
{
- PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_userdata(pool);
+ PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_user_data(pool);
MovieClip *clip = (MovieClip *)task_data;
uchar *mem;
size_t size;
@@ -942,9 +942,8 @@ static void start_prefetch_threads(MovieClip *clip,
float *progress)
{
PrefetchQueue queue;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
- int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
+ int i, tot_thread = BLI_task_scheduler_num_threads();
/* initialize queue */
BLI_spin_init(&queue.spin);
@@ -961,7 +960,7 @@ static void start_prefetch_threads(MovieClip *clip,
queue.do_update = do_update;
queue.progress = progress;
- task_pool = BLI_task_pool_create(task_scheduler, &queue, TASK_PRIORITY_LOW);
+ task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW);
for (i = 0; i < tot_thread; i++) {
BLI_task_pool_push(task_pool, prefetch_task_func, clip, false, NULL);
}
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 3204374b747..3783a3af96c 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -1367,10 +1367,10 @@ static uchar *proxy_thread_next_frame(ProxyQueue *queue,
return mem;
}
-static void proxy_task_func(TaskPool *__restrict pool, void *task_data, int UNUSED(threadid))
+static void proxy_task_func(TaskPool *__restrict pool, void *task_data)
{
ProxyThread *data = (ProxyThread *)task_data;
- ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_userdata(pool);
+ ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_user_data(pool);
uchar *mem;
size_t size;
int cfra;
@@ -1413,11 +1413,10 @@ static void do_sequence_proxy(void *pjv,
ProxyJob *pj = pjv;
MovieClip *clip = pj->clip;
Scene *scene = pj->scene;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
int sfra = SFRA, efra = EFRA;
ProxyThread *handles;
- int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
+ int i, tot_thread = BLI_task_scheduler_num_threads();
int width, height;
ProxyQueue queue;
@@ -1434,7 +1433,7 @@ static void do_sequence_proxy(void *pjv,
queue.do_update = do_update;
queue.progress = progress;
- task_pool = BLI_task_pool_create(task_scheduler, &queue, TASK_PRIORITY_LOW);
+ task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW);
handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles");
for (i = 0; i < tot_thread; i++) {
ProxyThread *handle = &handles[i];
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 4a0df454a78..03f791ad70d 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -166,7 +166,8 @@ static float calculate_reprojection_error_at_marker(MovieClip *clip,
reprojected_position[1] = (reprojected_position[1] / (reprojected_position[3] * 2.0f) + 0.5f) *
clip_height * aspy;
- BKE_tracking_distort_v2(tracking, reprojected_position, reprojected_position);
+ BKE_tracking_distort_v2(
+ tracking, clip_width, clip_height, reprojected_position, reprojected_position);
marker_position[0] = (marker->pos[0] + track->offset[0]) * clip_width;
marker_position[1] = (marker->pos[1] + track->offset[1]) * clip_height * aspy;
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index c2a4ebdfc63..7f58f30d2d2 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -598,8 +598,8 @@ void CLIP_OT_select_box(wmOperatorType *ot)
/********************** lasso select operator *********************/
static int do_lasso_select_marker(bContext *C,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const short mcoords_len,
bool select)
{
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -616,7 +616,7 @@ static int do_lasso_select_marker(bContext *C,
int framenr = ED_space_clip_get_clip_frame_number(sc);
/* get rectangle from operator */
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* do actual selection */
track = tracksbase->first;
@@ -631,7 +631,8 @@ static int do_lasso_select_marker(bContext *C,
ED_clip_point_stable_pos__reverse(sc, region, marker->pos, screen_co);
if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
if (select) {
BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
}
@@ -659,7 +660,8 @@ static int do_lasso_select_marker(bContext *C,
ED_clip_point_stable_pos__reverse(sc, region, plane_marker->corners[i], screen_co);
if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
if (select) {
plane_track->flag |= SELECT;
}
@@ -685,10 +687,10 @@ static int do_lasso_select_marker(bContext *C,
static int clip_lasso_select_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
@@ -696,9 +698,9 @@ static int clip_lasso_select_exec(bContext *C, wmOperator *op)
ED_clip_select_all(sc, SEL_DESELECT, NULL);
}
- do_lasso_select_marker(C, mcords, mcords_tot, select);
+ do_lasso_select_marker(C, mcoords, mcoords_len, select);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index ac8fa413f07..7f6d0658ec8 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1264,11 +1264,9 @@ static void filelist_intern_free(FileListIntern *filelist_intern)
MEM_SAFE_FREE(filelist_intern->filtered);
}
-static void filelist_cache_preview_runf(TaskPool *__restrict pool,
- void *taskdata,
- int UNUSED(threadid))
+static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
{
- FileListEntryCache *cache = BLI_task_pool_userdata(pool);
+ FileListEntryCache *cache = BLI_task_pool_user_data(pool);
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
FileListEntryPreview *preview = preview_taskdata->preview;
@@ -1306,9 +1304,7 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool,
// printf("%s: End (%d)...\n", __func__, threadid);
}
-static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
FileListEntryPreview *preview = preview_taskdata->preview;
@@ -1327,9 +1323,7 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool),
static void filelist_cache_preview_ensure_running(FileListEntryCache *cache)
{
if (!cache->previews_pool) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
-
- cache->previews_pool = BLI_task_pool_create_background(scheduler, cache, TASK_PRIORITY_LOW);
+ cache->previews_pool = BLI_task_pool_create_background(cache, TASK_PRIORITY_LOW);
cache->previews_done = BLI_thread_queue_init();
IMB_thumb_locks_acquire();
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 8c931a0c4a3..6c984860efc 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -42,6 +42,7 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_screen.h"
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index a2e9ba86dec..ae435b5624a 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -760,8 +760,8 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
data_lasso.rectf_view = &rect_fl;
- data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
- if (data_lasso.mcords == NULL) {
+ data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcoords_len);
+ if (data_lasso.mcoords == NULL) {
return OPERATOR_CANCELLED;
}
@@ -782,13 +782,13 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
/* get settings from operator */
- BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_lasso_boundbox(&rect, data_lasso.mcoords, data_lasso.mcoords_len);
BLI_rctf_rcti_copy(&rect_fl, &rect);
/* apply box_select action */
box_select_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
- MEM_freeN((void *)data_lasso.mcords);
+ MEM_freeN((void *)data_lasso.mcoords);
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 7f911113b7c..c9f2ec38354 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -264,7 +264,10 @@ void ED_space_image_get_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
}
}
-void ED_space_image_get_zoom(SpaceImage *sima, ARegion *region, float *r_zoomx, float *r_zoomy)
+void ED_space_image_get_zoom(SpaceImage *sima,
+ const ARegion *region,
+ float *r_zoomx,
+ float *r_zoomy)
{
int width, height;
@@ -314,7 +317,7 @@ void ED_image_get_uv_aspect(Image *ima, ImageUser *iuser, float *r_aspx, float *
}
/* takes event->mval */
-void ED_image_mouse_pos(SpaceImage *sima, ARegion *region, const int mval[2], float co[2])
+void ED_image_mouse_pos(SpaceImage *sima, const ARegion *region, const int mval[2], float co[2])
{
int sx, sy, width, height;
float zoomx, zoomy;
@@ -341,7 +344,7 @@ void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
}
void ED_image_point_pos(
- SpaceImage *sima, ARegion *region, float x, float y, float *r_x, float *r_y)
+ SpaceImage *sima, const ARegion *region, float x, float y, float *r_x, float *r_y)
{
int sx, sy, width, height;
float zoomx, zoomy;
@@ -356,7 +359,7 @@ void ED_image_point_pos(
}
void ED_image_point_pos__reverse(SpaceImage *sima,
- ARegion *region,
+ const ARegion *region,
const float co[2],
float r_co[2])
{
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 1e1d4373fea..d7d85112497 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -127,6 +127,7 @@ static SpaceLink *image_new(const ScrArea *UNUSED(area), const Scene *UNUSED(sce
simage->zoom = 1.0f;
simage->lock = true;
simage->flag = SI_SHOW_GPENCIL | SI_USE_ALPHA | SI_COORDFLOATS;
+ simage->uv_opacity = 1.0f;
BKE_imageuser_default(&simage->iuser);
simage->iuser.flag = IMA_SHOW_STEREO | IMA_ANIM_ALWAYS;
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index a91a11b2465..f8c0e66873f 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -33,6 +33,8 @@
#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
+#include "BLF_api.h"
+
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -59,9 +61,10 @@
#include "ED_armature.h"
#include "ED_info.h"
+#include "UI_resources.h"
+
#include "GPU_extensions.h"
-#define MAX_INFO_LEN 512
#define MAX_INFO_NUM_LEN 16
typedef struct SceneStats {
@@ -73,8 +76,6 @@ typedef struct SceneStats {
uint64_t totlamp, totlampsel;
uint64_t tottri;
uint64_t totgplayer, totgpframe, totgpstroke, totgppoint;
-
- char infostr[MAX_INFO_LEN];
} SceneStats;
typedef struct SceneStatsFmt {
@@ -368,10 +369,16 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
if (obedit) {
/* Edit Mode */
- FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, ((View3D *)NULL), ob->type, ob->mode, ob_iter) {
- stats_object_edit(ob_iter, &stats);
+ FOREACH_OBJECT_BEGIN (view_layer, ob_iter) {
+ if (ob_iter->base_flag & BASE_VISIBLE_VIEWLAYER) {
+ if (ob_iter->mode == OB_MODE_EDIT) {
+ stats_object_edit(ob_iter, &stats);
+ stats.totobjsel++;
+ }
+ stats.totobj++;
+ }
}
- FOREACH_OBJECT_IN_MODE_END;
+ FOREACH_OBJECT_END;
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
/* Pose Mode */
@@ -398,26 +405,98 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
*(view_layer->stats) = stats;
}
-static void stats_string(ViewLayer *view_layer)
+static const char *footer_string(ViewLayer *view_layer)
{
#define MAX_INFO_MEM_LEN 64
- SceneStats *stats = view_layer->stats;
- SceneStatsFmt stats_fmt;
- LayerCollection *layer_collection = view_layer->active_collection;
- Object *ob = OBACT(view_layer);
- Object *obedit = OBEDIT_FROM_OBACT(ob);
- eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
- uintptr_t mem_in_use, mmap_in_use;
char memstr[MAX_INFO_MEM_LEN];
char gpumemstr[MAX_INFO_MEM_LEN] = "";
char formatted_mem[15];
- char *s;
size_t ofs = 0;
- mem_in_use = MEM_get_memory_in_use();
- mmap_in_use = MEM_get_mapped_memory_in_use();
+ uintptr_t mem_in_use = MEM_get_memory_in_use();
+ uintptr_t mmap_in_use = MEM_get_mapped_memory_in_use();
+
+ /* get memory statistics */
+ BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, false);
+ ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_("Mem: %s"), formatted_mem);
+
+ if (mmap_in_use) {
+ BLI_str_format_byte_unit(formatted_mem, mmap_in_use, false);
+ BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_(" (%s)"), formatted_mem);
+ }
+
+ if (GPU_mem_stats_supported()) {
+ int gpu_free_mem, gpu_tot_memory;
+
+ GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
+
+ BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false);
+ ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem);
+
+ if (gpu_tot_memory) {
+ BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false);
+ BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem);
+ }
+ }
+
+ BLI_snprintf(view_layer->footer_str,
+ sizeof(view_layer->footer_str),
+ "%s%s | %s",
+ memstr,
+ gpumemstr,
+ versionstr);
+
+ return view_layer->footer_str;
+
+#undef MAX_INFO_MEM_LEN
+}
+
+void ED_info_stats_clear(ViewLayer *view_layer)
+{
+ if (view_layer->stats) {
+ MEM_freeN(view_layer->stats);
+ view_layer->stats = NULL;
+ }
+}
+
+const char *ED_info_footer_string(ViewLayer *view_layer)
+{
+ return footer_string(view_layer);
+}
+
+static void stats_row(int col1,
+ const char *key,
+ int col2,
+ const char *value1,
+ const char *value2,
+ int *y,
+ int height)
+{
+ *y -= height;
+ BLF_draw_default(col1, *y, 0.0f, key, 128);
+ char values[128];
+ BLI_snprintf(values, sizeof(values), (value2) ? "%s / %s" : "%s", value1, value2);
+ BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
+}
+
+void ED_info_draw_stats(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height)
+{
+ /* Create stats if they don't already exist. */
+ if (!view_layer->stats) {
+ /* Do not not access dependency graph if interface is marked as locked. */
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm->is_interface_locked) {
+ return;
+ }
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
+ stats_update(depsgraph, view_layer);
+ }
- /* Generate formatted numbers */
+ SceneStats *stats = view_layer->stats;
+ SceneStatsFmt stats_fmt;
+
+ /* Generate formatted numbers. */
#define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt._id, stats->_id)
SCENE_STATS_FMT_INT(totvert);
@@ -447,151 +526,94 @@ static void stats_string(ViewLayer *view_layer)
#undef SCENE_STATS_FMT_INT
- /* get memory statistics */
- BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, false);
- ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_(" | Mem: %s"), formatted_mem);
-
- if (mmap_in_use) {
- BLI_str_format_byte_unit(formatted_mem, mmap_in_use, false);
- BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_(" (%s)"), formatted_mem);
+ Object *ob = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_OBACT(ob);
+ eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
+ const int font_id = BLF_default();
+
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
+ BLF_enable(font_id, BLF_SHADOW);
+ BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
+ BLF_shadow_offset(font_id, 1, -1);
+
+ /* Translated labels for each stat row. */
+ enum {
+ OBJ,
+ VERTS,
+ EDGES,
+ FACES,
+ TRIS,
+ BONES,
+ LAYERS,
+ FRAMES,
+ STROKES,
+ POINTS,
+ MAX_LABELS_COUNT
+ };
+ char labels[MAX_LABELS_COUNT][64];
+
+ STRNCPY(labels[OBJ], IFACE_("Objects"));
+ STRNCPY(labels[VERTS], IFACE_("Vertices"));
+ STRNCPY(labels[EDGES], IFACE_("Edges"));
+ STRNCPY(labels[FACES], IFACE_("Faces"));
+ STRNCPY(labels[TRIS], IFACE_("Triangles"));
+ STRNCPY(labels[BONES], IFACE_("Bones"));
+ STRNCPY(labels[LAYERS], IFACE_("Layers"));
+ STRNCPY(labels[FRAMES], IFACE_("Frames"));
+ STRNCPY(labels[STROKES], IFACE_("Strokes"));
+ STRNCPY(labels[POINTS], IFACE_("Points"));
+
+ int longest_label = 0;
+ int i;
+ for (i = 0; i < MAX_LABELS_COUNT; ++i) {
+ longest_label = max_ii(longest_label, BLF_width(font_id, labels[i], sizeof(labels[i])));
}
- if (GPU_mem_stats_supported()) {
- int gpu_free_mem, gpu_tot_memory;
-
- GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
-
- BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false);
- ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem);
-
- if (gpu_tot_memory) {
- BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false);
- BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem);
- }
- }
+ int col1 = x;
+ int col2 = x + longest_label + (0.5f * U.widget_unit);
- s = stats->infostr;
- ofs = 0;
+ /* Add some extra margin above this section. */
+ *y -= (0.6f * height);
if (object_mode == OB_MODE_OBJECT) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- "%s | ",
- BKE_collection_ui_name_get(layer_collection->collection));
- }
-
- if (ob) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", ob->id.name + 2);
+ stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
}
if (obedit) {
- if (BKE_keyblock_from_object(obedit)) {
- ofs += BLI_strncpy_rlen(s + ofs, TIP_("(Key) "), MAX_INFO_LEN - ofs);
- }
-
if (obedit->type == OB_MESH) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"),
- stats_fmt.totvertsel,
- stats_fmt.totvert,
- stats_fmt.totedgesel,
- stats_fmt.totedge,
- stats_fmt.totfacesel,
- stats_fmt.totface,
- stats_fmt.tottri);
+ stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
+ stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
+ stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
}
else if (obedit->type == OB_ARMATURE) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s/%s | Bones:%s/%s"),
- stats_fmt.totvertsel,
- stats_fmt.totvert,
- stats_fmt.totbonesel,
- stats_fmt.totbone);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
+ stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
}
else {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s/%s"),
- stats_fmt.totvertsel,
- stats_fmt.totvert);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
}
-
- ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
- ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
}
else if (ob && (object_mode & OB_MODE_POSE)) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Bones:%s/%s %s%s"),
- stats_fmt.totbonesel,
- stats_fmt.totbone,
- memstr,
- gpumemstr);
+ stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
}
else if ((ob) && (ob->type == OB_GPENCIL)) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Layers:%s | Frames:%s | Strokes:%s | Points:%s | Objects:%s/%s"),
- stats_fmt.totgplayer,
- stats_fmt.totgpframe,
- stats_fmt.totgpstroke,
- stats_fmt.totgppoint,
- stats_fmt.totobjsel,
- stats_fmt.totobj);
-
- ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
- ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
+ stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, NULL, y, height);
+ stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, NULL, y, height);
+ stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, NULL, y, height);
+ stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, NULL, y, height);
}
else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s | Tris:%s%s"),
- stats_fmt.totvert,
- stats_fmt.tottri,
- gpumemstr);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
}
else {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s%s%s"),
- stats_fmt.totvert,
- stats_fmt.totface,
- stats_fmt.tottri,
- stats_fmt.totobjsel,
- stats_fmt.totobj,
- memstr,
- gpumemstr);
- }
-
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", versionstr);
-#undef MAX_INFO_MEM_LEN
-}
-
-#undef MAX_INFO_LEN
-
-void ED_info_stats_clear(ViewLayer *view_layer)
-{
- if (view_layer->stats) {
- MEM_freeN(view_layer->stats);
- view_layer->stats = NULL;
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height);
+ stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, NULL, y, height);
+ stats_row(col1, labels[FACES], col2, stats_fmt.totface, NULL, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
}
-}
-const char *ED_info_stats_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
-{
- /* Looping through dependency graph when interface is locked is not safe.
- * The interface is marked as locked when jobs wants to modify the
- * dependency graph. */
- wmWindowManager *wm = bmain->wm.first;
- if (wm->is_interface_locked) {
- return "";
- }
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
- if (!view_layer->stats) {
- stats_update(depsgraph, view_layer);
- }
- stats_string(view_layer);
- return view_layer->stats->infostr;
+ BLF_disable(font_id, BLF_SHADOW);
}
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 218e2be0362..307b6d9bc21 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -143,7 +143,8 @@ bool nla_panel_context(const bContext *C,
case ANIMTYPE_PALETTE:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* for these channels, we only do AnimData */
if (ale->adt && adt_ptr) {
ID *id;
@@ -354,7 +355,7 @@ static void nla_panel_properties(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
uiLayout *layout = panel->layout;
- uiLayout *column;
+ uiLayout *column, *row;
uiBlock *block;
short showEvalProps = 1;
@@ -401,20 +402,19 @@ static void nla_panel_properties(const bContext *C, Panel *panel)
uiItemR(column, &strip_ptr, "blend_in", 0, IFACE_("Blend In"), ICON_NONE);
uiItemR(column, &strip_ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE);
- column = uiLayoutColumn(layout, true);
- uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_influence") == false);
- uiItemR(column, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE); // XXX as toggle?
-
- uiItemS(layout);
+ row = uiLayoutRow(column, true);
+ uiLayoutSetActive(row, RNA_boolean_get(&strip_ptr, "use_animated_influence") == false);
+ uiItemR(row, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE); // XXX as toggle?
/* settings */
- column = uiLayoutColumn(layout, true);
- uiLayoutSetActive(column,
+ column = uiLayoutColumnWithHeading(layout, true, "Playback");
+ row = uiLayoutRow(column, true);
+ uiLayoutSetActive(row,
!(RNA_boolean_get(&strip_ptr, "use_animated_influence") ||
RNA_boolean_get(&strip_ptr, "use_animated_time")));
- uiItemR(column, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
+ uiItemR(row, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
- uiItemR(layout, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE);
+ uiItemR(column, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE);
}
}
@@ -442,15 +442,12 @@ static void nla_panel_actclip(const bContext *C, Panel *panel)
uiItemR(row, &strip_ptr, "action", 0, NULL, ICON_ACTION);
/* action extents */
- // XXX custom names were used here (to avoid the prefixes)... probably not necessary in future?
column = uiLayoutColumn(layout, true);
uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Frame Start"), ICON_NONE);
uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End"), ICON_NONE);
- /* XXX: this layout may actually be too abstract and confusing,
- * and may be better using standard column layout. */
- row = uiLayoutRow(layout, false);
- uiItemR(row, &strip_ptr, "use_sync_length", 0, IFACE_("Sync Length"), ICON_NONE);
+ row = uiLayoutRowWithHeading(layout, false, "Sync Length");
+ uiItemR(row, &strip_ptr, "use_sync_length", 0, "", ICON_NONE);
uiItemO(row, IFACE_("Now"), ICON_FILE_REFRESH, "NLA_OT_action_sync_length");
/* action usage */
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 5adcec8a5d7..d399ea47d7e 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -193,7 +193,8 @@ static int mouse_nla_channels(
case ANIMTYPE_PALETTE:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* sanity checking... */
if (ale->adt) {
/* select/deselect */
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index f8c30f9a688..4e21cdc9d16 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -75,6 +75,10 @@ if(WITH_OPENIMAGEDENOISE)
add_definitions(-DWITH_OPENIMAGEDENOISE)
endif()
+if (WITH_NEW_SIMULATION_TYPE)
+ add_definitions(-DWITH_NEW_SIMULATION_TYPE)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index e5ca2efb26f..44003a5b9bc 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -69,9 +69,13 @@
#include "NOD_composite.h"
#include "NOD_shader.h"
+#include "NOD_simulation.h"
#include "NOD_texture.h"
#include "node_intern.h" /* own include */
+/* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */
+#define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME
+
/* ****************** SOCKET BUTTON DRAW FUNCTIONS ***************** */
static void node_socket_button_label(bContext *UNUSED(C),
@@ -93,7 +97,7 @@ static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *p
PointerRNA sockptr;
RNA_pointer_create(ptr->owner_id, &RNA_NodeSocket, output, &sockptr);
- uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -107,7 +111,7 @@ static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr
col = uiLayoutColumn(layout, false);
uiTemplateColorPicker(col, &sockptr, "default_value", 1, 0, 0, 0);
- uiItemR(col, &sockptr, "default_value", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(col, &sockptr, "default_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
}
static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -118,12 +122,12 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE);
if (ELEM(ntree->type, NTREE_COMPOSIT, NTREE_TEXTURE)) {
- uiItemR(row, ptr, "use_alpha", 0, "", ICON_IMAGE_RGB_ALPHA);
+ uiItemR(row, ptr, "use_alpha", DEFAULT_FLAGS, "", ICON_IMAGE_RGB_ALPHA);
}
- uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -145,8 +149,8 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "frame_start", 0, IFACE_("Sta"), ICON_NONE);
- uiItemR(row, ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
+ uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Sta"), ICON_NONE);
+ uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
}
static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -196,7 +200,7 @@ static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA *
PointerRNA sockptr;
RNA_pointer_create(ptr->owner_id, &RNA_NodeSocket, output, &sockptr);
- uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
}
#if 0 /* not used in 2.5x yet */
@@ -242,33 +246,33 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
short multi = (node->id && ((Tex *)node->id)->use_nodes && (node->type != CMP_NODE_TEXTURE) &&
(node->type != TEX_NODE_TEXTURE));
- uiItemR(layout, ptr, "texture", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "texture", DEFAULT_FLAGS, "", ICON_NONE);
if (multi) {
/* Number Drawing not optimal here, better have a list*/
- uiItemR(layout, ptr, "node_output", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "node_output", DEFAULT_FLAGS, "", ICON_NONE);
}
}
static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "clamp_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "clamp_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE);
if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
NODE_MAP_RANGE_SMOOTHSTEP,
NODE_MAP_RANGE_SMOOTHERSTEP)) {
- uiItemR(layout, ptr, "clamp", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static int node_resize_area_default(bNode *node, int x, int y)
@@ -534,9 +538,9 @@ static int node_resize_area_frame(bNode *node, int x, int y)
static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "label_size", 0, IFACE_("Label Size"), ICON_NONE);
- uiItemR(layout, ptr, "shrink", 0, IFACE_("Shrink"), ICON_NONE);
- uiItemR(layout, ptr, "text", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "label_size", DEFAULT_FLAGS, IFACE_("Label Size"), ICON_NONE);
+ uiItemR(layout, ptr, "shrink", DEFAULT_FLAGS, IFACE_("Shrink"), ICON_NONE);
+ uiItemR(layout, ptr, "text", DEFAULT_FLAGS, NULL, ICON_NONE);
}
#define NODE_REROUTE_SIZE 8.0f
@@ -697,7 +701,7 @@ static void node_buts_image_user(uiLayout *layout,
col = uiLayoutColumn(layout, false);
- uiItemR(col, imaptr, "source", 0, "", ICON_NONE);
+ uiItemR(col, imaptr, "source", DEFAULT_FLAGS, "", ICON_NONE);
source = RNA_enum_get(imaptr, "source");
@@ -716,23 +720,23 @@ static void node_buts_image_user(uiLayout *layout,
if (ELEM(source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "frame_duration", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "frame_start", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "frame_offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_cyclic", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "frame_duration", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "frame_offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_cyclic", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_auto_refresh", DEFAULT_FLAGS, NULL, ICON_NONE);
}
if (compositor && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
RNA_boolean_get(ptr, "has_layers")) {
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "layer", DEFAULT_FLAGS, NULL, ICON_NONE);
}
uiLayout *split = uiLayoutSplit(layout, 0.5f, true);
PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings");
uiItemL(split, IFACE_("Color Space"), ICON_NONE);
- uiItemR(split, &colorspace_settings_ptr, "name", 0, "", ICON_NONE);
+ uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
/* Avoid losing changes image is painted. */
if (BKE_image_is_dirty(imaptr->data)) {
@@ -742,35 +746,35 @@ static void node_buts_image_user(uiLayout *layout,
static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "vector_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "rotation_type", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "invert", 0, NULL, 0);
+ uiItemR(layout, ptr, "rotation_type", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(layout, ptr, "convert_from", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "convert_to", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "convert_from", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "convert_to", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "attribute_name", 0, IFACE_("Name"), ICON_NONE);
+ uiItemR(layout, ptr, "attribute_name", DEFAULT_FLAGS, IFACE_("Name"), ICON_NONE);
}
static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_pixel_size", 0, NULL, 0);
+ uiItemR(layout, ptr, "use_pixel_size", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -789,14 +793,14 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
UI_TEMPLATE_ID_FILTER_ALL,
false,
NULL);
- uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "projection") == SHD_PROJ_BOX) {
- uiItemR(layout, ptr, "projection_blend", 0, "Blend", ICON_NONE);
+ uiItemR(layout, ptr, "projection_blend", DEFAULT_FLAGS, "Blend", ICON_NONE);
}
- uiItemR(layout, ptr, "extension", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "extension", DEFAULT_FLAGS, "", ICON_NONE);
/* note: image user properties used directly here, unlike compositor image node,
* which redefines them in the node struct RNA to get proper updates.
@@ -827,8 +831,8 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
false,
NULL);
- uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE);
node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
}
@@ -838,29 +842,29 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0);
- uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE);
- uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, IFACE_("Interpolation"), ICON_NONE);
+ uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, IFACE_("Projection"), ICON_NONE);
}
static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "sky_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "turbidity", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NEW) {
- uiItemR(layout, ptr, "ground_albedo", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "gradient_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "gradient_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "turbulence_depth", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "turbulence_depth", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -868,48 +872,48 @@ static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
- uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
+ uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE);
- uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE);
+ uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
}
static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "wave_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "wave_type", DEFAULT_FLAGS, "", ICON_NONE);
int type = RNA_enum_get(ptr, "wave_type");
if (type == SHD_WAVE_BANDS) {
- uiItemR(layout, ptr, "bands_direction", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "bands_direction", DEFAULT_FLAGS, "", ICON_NONE);
}
else { /* SHD_WAVE_RINGS */
- uiItemR(layout, ptr, "rings_direction", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "rings_direction", DEFAULT_FLAGS, "", ICON_NONE);
}
- uiItemR(layout, ptr, "wave_profile", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "wave_profile", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "musgrave_dimensions", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "musgrave_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "musgrave_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "voronoi_dimensions", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "feature", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "voronoi_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "feature", DEFAULT_FLAGS, "", ICON_NONE);
int feature = RNA_enum_get(ptr, "feature");
if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
- uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, "", ICON_NONE);
}
}
static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_pointdensity(uiLayout *layout,
@@ -925,7 +929,7 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout,
RNA_id_pointer_create(ob ? (ID *)ob->data : NULL, &obdata_ptr);
uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "object", DEFAULT_FLAGS, NULL, ICON_NONE);
if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
PointerRNA dataptr;
@@ -933,15 +937,15 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout,
uiItemPointerR(layout, ptr, "particle_system", &dataptr, "particle_systems", NULL, ICON_NONE);
}
- uiItemR(layout, ptr, "space", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "radius", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "interpolation", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "resolution", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "radius", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "resolution", DEFAULT_FLAGS, NULL, ICON_NONE);
if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- uiItemR(layout, ptr, "particle_color_source", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "particle_color_source", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
- uiItemR(layout, ptr, "vertex_color_source", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "vertex_color_source", DEFAULT_FLAGS, NULL, ICON_NONE);
if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) {
if (ob_ptr.data) {
uiItemPointerR(
@@ -959,18 +963,18 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout,
static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "object", 0, NULL, 0);
- uiItemR(layout, ptr, "from_instancer", 0, NULL, 0);
+ uiItemR(layout, ptr, "object", DEFAULT_FLAGS, NULL, 0);
+ uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "invert", 0, NULL, 0);
+ uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiItemR(layout, ptr, "from_instancer", 0, NULL, 0);
+ uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, NULL, 0);
if (!RNA_boolean_get(ptr, "from_instancer")) {
PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
@@ -996,12 +1000,12 @@ static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, Pointer
static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_tips", 0, NULL, 0);
+ uiItemR(layout, ptr, "use_tips", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiItemR(layout, ptr, "space", 0, "", 0);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) {
PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
@@ -1011,14 +1015,14 @@ static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRN
uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
}
else {
- uiItemR(layout, ptr, "uv_map", 0, "", 0);
+ uiItemR(layout, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
}
}
}
static void node_shader_buts_displacement(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "space", 0, "", 0);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
}
static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1027,7 +1031,7 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *
split = uiLayoutSplit(layout, 0.0f, false);
- uiItemR(split, ptr, "direction_type", 0, "", 0);
+ uiItemR(split, ptr, "direction_type", DEFAULT_FLAGS, "", 0);
row = uiLayoutRow(split, false);
@@ -1039,50 +1043,50 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *
uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
}
else {
- uiItemR(row, ptr, "uv_map", 0, "", 0);
+ uiItemR(row, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
}
}
else {
- uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, 0);
+ uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, 0);
}
}
static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "subsurface_method", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "subsurface_method", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "falloff", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_principled_hair(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "parametrization", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "parametrization", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1090,15 +1094,15 @@ static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerR
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) {
- uiItemR(row, ptr, "ies", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "ies", DEFAULT_FLAGS, "", ICON_NONE);
}
else {
- uiItemR(row, ptr, "filepath", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
}
@@ -1107,15 +1111,15 @@ static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), Point
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) {
- uiItemR(row, ptr, "script", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "script", DEFAULT_FLAGS, "", ICON_NONE);
}
else {
- uiItemR(row, ptr, "filepath", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update");
@@ -1129,14 +1133,14 @@ static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA
#if 0 /* not implemented yet */
if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) {
- uiItemR(layout, ptr, "use_auto_update", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_auto_update", DEFAULT_FLAGS, NULL, ICON_NONE);
}
#endif
}
static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "target", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "target", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1145,32 +1149,32 @@ static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), Po
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE);
- uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_ambient_occlusion(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "inside", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "only_local", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "inside", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "only_local", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "name", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "name", DEFAULT_FLAGS, NULL, ICON_NONE);
}
/* only once called */
@@ -1355,10 +1359,10 @@ static void node_buts_image_views(uiLayout *layout,
if (RNA_boolean_get(ptr, "has_views")) {
if (RNA_enum_get(ptr, "view") == 0) {
- uiItemR(col, ptr, "view", 0, NULL, ICON_CAMERA_STEREO);
+ uiItemR(col, ptr, "view", DEFAULT_FLAGS, NULL, ICON_CAMERA_STEREO);
}
else {
- uiItemR(col, ptr, "view", 0, NULL, ICON_SCENE);
+ uiItemR(col, ptr, "view", DEFAULT_FLAGS, NULL, ICON_SCENE);
}
}
}
@@ -1419,7 +1423,7 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "layer", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE);
prop = RNA_struct_find_property(ptr, "layer");
if (!(RNA_property_enum_identifier(
@@ -1446,56 +1450,56 @@ static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), Point
filter = RNA_enum_get(ptr, "filter_type");
reference = RNA_boolean_get(ptr, "use_variable_size");
- uiItemR(col, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
if (filter != R_FILTER_FAST_GAUSS) {
- uiItemR(col, ptr, "use_variable_size", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_variable_size", DEFAULT_FLAGS, NULL, ICON_NONE);
if (!reference) {
- uiItemR(col, ptr, "use_bokeh", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_bokeh", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "use_gamma_correction", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_gamma_correction", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "use_relative", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_relative", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_boolean_get(ptr, "use_relative")) {
uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "aspect_correction", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "aspect_correction", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "factor_x", 0, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "factor_y", 0, IFACE_("Y"), ICON_NONE);
+ uiItemR(col, ptr, "factor_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "factor_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
}
else {
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "size_x", 0, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "size_y", 0, IFACE_("Y"), ICON_NONE);
+ uiItemR(col, ptr, "size_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "size_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
}
- uiItemR(col, ptr, "use_extended_bounds", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_extended_bounds", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *col;
- uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_wrap", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_wrap", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Center:"), ICON_NONE);
- uiItemR(col, ptr, "center_x", 0, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "center_y", 0, IFACE_("Y"), ICON_NONE);
+ uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
uiItemS(layout);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "distance", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE);
uiItemS(layout);
- uiItemR(layout, ptr, "spin", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "zoom", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "spin", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "zoom", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_bilateralblur(uiLayout *layout,
@@ -1505,9 +1509,9 @@ static void node_composit_buts_bilateralblur(uiLayout *layout,
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "iterations", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "sigma_color", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "sigma_space", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "sigma_color", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "sigma_space", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1516,60 +1520,60 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA
col = uiLayoutColumn(layout, false);
uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE);
- uiItemR(col, ptr, "bokeh", 0, "", ICON_NONE);
- uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "bokeh", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_gamma_correction", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_gamma_correction", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true);
- uiItemR(col, ptr, "f_stop", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "f_stop", DEFAULT_FLAGS, NULL, ICON_NONE);
- uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false);
- uiItemR(sub, ptr, "z_scale", 0, NULL, ICON_NONE);
+ uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, NULL, ICON_NONE);
}
/* qdn: glare node */
static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "glare_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "quality", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "glare_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "quality", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") != 1) {
- uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") != 0) {
- uiItemR(layout, ptr, "color_modulation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "color_modulation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
}
- uiItemR(layout, ptr, "mix", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mix", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "streaks", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "angle_offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "streaks", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "angle_offset", DEFAULT_FLAGS, NULL, ICON_NONE);
}
if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "fade", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "fade", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") == 0) {
- uiItemR(layout, ptr, "use_rotate_45", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_rotate_45", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
if (RNA_enum_get(ptr, "glare_type") == 1) {
- uiItemR(layout, ptr, "size", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "size", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -1578,17 +1582,17 @@ static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tonemap_type", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "tonemap_type", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "tonemap_type") == 0) {
- uiItemR(col, ptr, "key", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "gamma", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "key", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
- uiItemR(col, ptr, "intensity", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "adaptation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "correction", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "intensity", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "adaptation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "correction", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
}
@@ -1597,12 +1601,12 @@ static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), P
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_projector", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_projector", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(col, false);
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
- uiItemR(col, ptr, "use_jitter", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_fit", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_jitter", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_fit", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1610,46 +1614,46 @@ static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "samples", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "factor", 0, IFACE_("Blur"), ICON_NONE);
+ uiItemR(col, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "factor", DEFAULT_FLAGS, IFACE_("Blur"), ICON_NONE);
col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Speed:"), ICON_NONE);
- uiItemR(col, ptr, "speed_min", 0, IFACE_("Min"), ICON_NONE);
- uiItemR(col, ptr, "speed_max", 0, IFACE_("Max"), ICON_NONE);
+ uiItemR(col, ptr, "speed_min", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE);
+ uiItemR(col, ptr, "speed_max", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE);
- uiItemR(layout, ptr, "use_curved", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_curved", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "axis", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "axis", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *col;
- uiItemR(layout, ptr, "use_crop_size", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "relative", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_crop_size", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "relative", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
if (RNA_boolean_get(ptr, "relative")) {
- uiItemR(col, ptr, "rel_min_x", 0, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_x", 0, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "rel_min_y", 0, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_y", 0, IFACE_("Down"), ICON_NONE);
+ uiItemR(col, ptr, "rel_min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "rel_min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
}
else {
- uiItemR(col, ptr, "min_x", 0, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "max_x", 0, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "min_y", 0, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "max_y", 0, IFACE_("Down"), ICON_NONE);
+ uiItemR(col, ptr, "min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
}
}
@@ -1659,8 +1663,8 @@ static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C)
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, ptr, "factor", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(col, ptr, "factor", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_double_edge_mask(uiLayout *layout,
@@ -1672,9 +1676,9 @@ static void node_composit_buts_double_edge_mask(uiLayout *layout,
col = uiLayoutColumn(layout, false);
uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
- uiItemR(col, ptr, "inner_mode", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "inner_mode", DEFAULT_FLAGS, "", ICON_NONE);
uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE);
- uiItemR(col, ptr, "edge_mode", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "edge_mode", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1682,7 +1686,7 @@ static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1690,20 +1694,20 @@ static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C),
uiLayout *sub, *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "size", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "size", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_min", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_min", DEFAULT_FLAGS, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
- uiItemR(sub, ptr, "min", 0, "", ICON_NONE);
+ uiItemR(sub, ptr, "min", DEFAULT_FLAGS, "", ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_max", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_max", DEFAULT_FLAGS, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
- uiItemR(sub, ptr, "max", 0, "", ICON_NONE);
+ uiItemR(sub, ptr, "max", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1711,8 +1715,8 @@ static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_premultiply", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "premul", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_premultiply", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "premul", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1720,27 +1724,27 @@ static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), P
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_alpha", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_antialias_z", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_antialias_z", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE);
switch (RNA_enum_get(ptr, "mode")) {
case CMP_NODE_DILATEERODE_DISTANCE_THRESH:
- uiItemR(layout, ptr, "edge", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "edge", DEFAULT_FLAGS, NULL, ICON_NONE);
break;
case CMP_NODE_DILATEERODE_DISTANCE_FEATHER:
- uiItemR(layout, ptr, "falloff", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, NULL, ICON_NONE);
break;
}
}
static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1748,8 +1752,8 @@ static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "threshold_neighbor", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "threshold_neighbor", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1757,8 +1761,8 @@ static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_distance_matte(uiLayout *layout,
@@ -1771,10 +1775,10 @@ static void node_composit_buts_distance_matte(uiLayout *layout,
uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1783,23 +1787,23 @@ static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C)
uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "limit_method") == 0) {
uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "ratio", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_unspill", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "ratio", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_unspill", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_boolean_get(ptr, "use_unspill") == true) {
- uiItemR(col, ptr, "unspill_red", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "unspill_green", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "unspill_blue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "unspill_red", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "unspill_green", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "unspill_blue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
}
@@ -1808,12 +1812,12 @@ static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tolerance", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
/*uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); Removed for now */
- uiItemR(col, ptr, "gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
/*uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, NULL, ICON_NONE); Removed for now*/
}
@@ -1822,9 +1826,9 @@ static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C)
uiLayout *col;
col = uiLayoutColumn(layout, true);
- 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);
+ uiItemR(col, ptr, "color_hue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "color_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "color_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_channel_matte(uiLayout *layout,
@@ -1835,24 +1839,24 @@ static void node_composit_buts_channel_matte(uiLayout *layout,
uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "color_space", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "color_space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiItemL(col, IFACE_("Key Channel:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "matte_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "matte_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "limit_method") == 0) {
uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1860,19 +1864,19 @@ static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "index", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_antialiasing", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "index", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_antialiasing", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1886,7 +1890,7 @@ static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C)
else {
uiItemL(layout, IFACE_("Base Path:"), ICON_NONE);
}
- uiItemR(layout, ptr, "base_path", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "base_path", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
@@ -1972,7 +1976,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
uiItemL(col, IFACE_("Layer:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "name", 0, "", ICON_NONE);
+ uiItemR(row, &active_input_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
uiItemFullO(row,
"NODE_OT_output_file_remove_active_socket",
"",
@@ -1987,7 +1991,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
uiItemL(col, IFACE_("File Subpath:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "path", 0, "", ICON_NONE);
+ uiItemR(row, &active_input_ptr, "path", DEFAULT_FLAGS, "", ICON_NONE);
uiItemFullO(row,
"NODE_OT_output_file_remove_active_socket",
"",
@@ -2002,7 +2006,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Format:"), ICON_NONE);
- uiItemR(col, &active_input_ptr, "use_node_format", 0, NULL, ICON_NONE);
+ uiItemR(col, &active_input_ptr, "use_node_format", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format") == false);
@@ -2017,20 +2021,20 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "space", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
uiLayout *row;
- uiItemR(layout, ptr, "frame_method", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "frame_method", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "offset_x", 0, "X", ICON_NONE);
- uiItemR(row, ptr, "offset_y", 0, "Y", ICON_NONE);
+ uiItemR(row, ptr, "offset_x", DEFAULT_FLAGS, "X", ICON_NONE);
+ uiItemR(row, ptr, "offset_y", DEFAULT_FLAGS, "Y", ICON_NONE);
}
}
static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2038,25 +2042,25 @@ static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), Poi
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "invert_rgb", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "invert_alpha", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "invert_rgb", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "invert_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "mapping", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *split, *col, *row;
- uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "correction_method") == 0) {
@@ -2064,17 +2068,17 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "lift", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "lift", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "lift", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "gamma", 1, 1, 1, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gamma", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "gain", 1, 1, 1, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gain", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "gain", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
@@ -2082,46 +2086,46 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "offset", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "offset_basis", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "offset_basis", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "power", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "power", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "power", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "slope", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "slope", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "slope", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
static void node_composit_buts_colorbalance_ex(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "correction_method") == 0) {
uiTemplateColorPicker(layout, ptr, "lift", 1, 1, 0, 1);
- uiItemR(layout, ptr, "lift", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "lift", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "gamma", 1, 1, 1, 1);
- uiItemR(layout, ptr, "gamma", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "gain", 1, 1, 1, 1);
- uiItemR(layout, ptr, "gain", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "gain", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
uiTemplateColorPicker(layout, ptr, "offset", 1, 1, 0, 1);
- uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "power", 1, 1, 0, 1);
- uiItemR(layout, ptr, "power", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "power", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "slope", 1, 1, 0, 1);
- uiItemR(layout, ptr, "slope", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "slope", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2143,7 +2147,7 @@ static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C),
static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -2180,19 +2184,19 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe
return;
}
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "invert", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_relative", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "wrap_axis", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_relative", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "wrap_axis", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -2206,7 +2210,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po
return;
}
- uiItemR(layout, ptr, "distortion_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distortion_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_colorcorrection(uiLayout *layout,
@@ -2216,9 +2220,9 @@ static void node_composit_buts_colorcorrection(uiLayout *layout,
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "green", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "red", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "green", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "blue", DEFAULT_FLAGS, NULL, ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, "", ICON_NONE);
@@ -2230,39 +2234,39 @@ static void node_composit_buts_colorcorrection(uiLayout *layout,
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Master"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Highlights"), ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Midtones"), ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Shadows"), ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
@@ -2272,48 +2276,48 @@ static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "green", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "red", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "green", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "blue", DEFAULT_FLAGS, NULL, ICON_NONE);
row = layout;
uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Lift"), ICON_NONE);
- uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "check", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "check", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_switch_view_ex(uiLayout *layout,
@@ -2335,32 +2339,32 @@ static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *row;
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "y", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "y", DEFAULT_FLAGS, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "flaps", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "angle", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "rounding", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "catadioptric", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "shift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "flaps", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "rounding", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "catadioptric", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "shift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_variable_size", 0, NULL, ICON_NONE);
- // uiItemR(layout, ptr, "f_stop", 0, NULL, ICON_NONE); // UNUSED
- uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_extended_bounds", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_variable_size", DEFAULT_FLAGS, NULL, ICON_NONE);
+ // uiItemR(layout, ptr, "f_stop", DEFAULT_FLAGS, NULL, ICON_NONE); // UNUSED
+ uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_extended_bounds", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_backdrop_viewer(
@@ -2486,36 +2490,36 @@ static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C)
{
uiLayout *row;
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "y", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "y", DEFAULT_FLAGS, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *col;
- uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "tile_order", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "tile_order", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "tile_order") == 0) {
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "center_x", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "center_y", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2524,19 +2528,19 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p
bNode *node = ptr->data;
uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
- uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, NULL, ICON_NONE);
- uiItemR(layout, ptr, "size_source", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE);
if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) {
- uiItemR(layout, ptr, "size_x", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "size_y", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "size_x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "size_y", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, NULL, ICON_NONE);
if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2562,18 +2566,18 @@ static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), Poi
{
/* bNode *node = ptr->data; */ /* UNUSED */
- uiItemR(layout, ptr, "blur_pre", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "screen_balance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "despill_factor", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "despill_balance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_radius", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_tolerance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "clip_black", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "clip_white", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "dilate_distance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "feather_falloff", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "feather_distance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "blur_post", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "blur_pre", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "screen_balance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "despill_factor", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "despill_balance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_radius", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_tolerance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "clip_black", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "clip_white", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "dilate_distance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "feather_falloff", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "feather_distance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "blur_post", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -2605,13 +2609,13 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
}
else {
- uiItemR(layout, ptr, "track_name", 0, "", ICON_ANIM_DATA);
+ uiItemR(layout, ptr, "track_name", DEFAULT_FLAGS, "", ICON_ANIM_DATA);
}
- uiItemR(layout, ptr, "position", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "position", DEFAULT_FLAGS, NULL, ICON_NONE);
if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
- uiItemR(layout, ptr, "frame_relative", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "frame_relative", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
}
@@ -2650,10 +2654,10 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
}
}
- uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, NULL, ICON_NONE);
if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2665,8 +2669,8 @@ static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout),
static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "source", UI_ITEM_R_EXPAND, "", ICON_NONE);
- uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, "", ICON_NONE);
+ uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2679,7 +2683,7 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C)
uiTemplateCryptoPicker(row, ptr, "add");
uiTemplateCryptoPicker(row, ptr, "remove");
- uiItemR(col, ptr, "matte_id", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_cryptomatte_ex(uiLayout *layout,
@@ -2694,7 +2698,7 @@ static void node_composit_buts_brightcontrast(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_premultiply", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2707,7 +2711,7 @@ static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), Po
}
#endif
- uiItemR(layout, ptr, "use_hdr", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, NULL, ICON_NONE);
}
/* only once called */
@@ -2957,12 +2961,12 @@ static void node_texture_buts_bricks(uiLayout *layout, bContext *UNUSED(C), Poin
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
- uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
+ uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE);
- uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE);
+ uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
}
static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2979,68 +2983,73 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe
switch (tex->type) {
case TEX_BLEND:
- uiItemR(col, &tex_ptr, "progression", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "progression", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "use_flip_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "use_flip_axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
break;
case TEX_MARBLE:
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "marble_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "marble_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_basis_2", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
break;
case TEX_MAGIC:
- uiItemR(col, &tex_ptr, "noise_depth", 0, NULL, ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_depth", DEFAULT_FLAGS, NULL, ICON_NONE);
break;
case TEX_STUCCI:
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "stucci_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "stucci_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
break;
case TEX_WOOD:
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
- uiItemR(col, &tex_ptr, "wood_type", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "wood_type", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_basis_2", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
uiLayoutSetActive(row, !(ELEM(tex->stype, TEX_BAND, TEX_RING)));
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
break;
case TEX_CLOUDS:
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "cloud_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "cloud_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_depth", UI_ITEM_R_EXPAND, IFACE_("Depth"), ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(col,
+ &tex_ptr,
+ "noise_depth",
+ DEFAULT_FLAGS | UI_ITEM_R_EXPAND,
+ IFACE_("Depth"),
+ ICON_NONE);
break;
case TEX_DISTNOISE:
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_distortion", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_distortion", DEFAULT_FLAGS, "", ICON_NONE);
break;
case TEX_MUSGRAVE:
- uiItemR(col, &tex_ptr, "musgrave_type", 0, "", ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
break;
case TEX_VORONOI:
- uiItemR(col, &tex_ptr, "distance_metric", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "distance_metric", DEFAULT_FLAGS, "", ICON_NONE);
if (tex->vn_distm == TEX_MINKOVSKY) {
- uiItemR(col, &tex_ptr, "minkovsky_exponent", 0, NULL, ICON_NONE);
+ uiItemR(col, &tex_ptr, "minkovsky_exponent", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(col, &tex_ptr, "color_mode", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "color_mode", DEFAULT_FLAGS, "", ICON_NONE);
break;
}
}
@@ -3070,7 +3079,7 @@ static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA
static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filepath", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
/* only once called */
@@ -3122,6 +3131,96 @@ static void node_texture_set_butfunc(bNodeType *ntype)
}
}
+/* ****************** BUTTON CALLBACKS FOR SIMULATION NODES ***************** */
+
+static void node_simulation_buts_particle_simulation(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_particle_time_step_event(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_particle_attribute(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_set_particle_attribute(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_set_butfunc(bNodeType *ntype)
+{
+ switch (ntype->type) {
+ case SIM_NODE_PARTICLE_SIMULATION:
+ ntype->draw_buttons = node_simulation_buts_particle_simulation;
+ break;
+ case SIM_NODE_PARTICLE_TIME_STEP_EVENT:
+ ntype->draw_buttons = node_simulation_buts_particle_time_step_event;
+ break;
+ case SIM_NODE_PARTICLE_ATTRIBUTE:
+ ntype->draw_buttons = node_simulation_buts_particle_attribute;
+ break;
+ case SIM_NODE_SET_PARTICLE_ATTRIBUTE:
+ ntype->draw_buttons = node_simulation_buts_set_particle_attribute;
+ break;
+ case SIM_NODE_TIME:
+ ntype->draw_buttons = node_simulation_buts_time;
+ break;
+ }
+}
+
+/* ****************** BUTTON CALLBACKS FOR FUNCTION NODES ***************** */
+
+static void node_function_buts_boolean_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_function_buts_float_compare(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_function_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_function_set_butfunc(bNodeType *ntype)
+{
+ switch (ntype->type) {
+ case FN_NODE_BOOLEAN_MATH:
+ ntype->draw_buttons = node_function_buts_boolean_math;
+ break;
+ case FN_NODE_FLOAT_COMPARE:
+ ntype->draw_buttons = node_function_buts_float_compare;
+ break;
+ case FN_NODE_SWITCH:
+ ntype->draw_buttons = node_function_buts_switch;
+ break;
+ }
+}
+
/* ****** init draw callbacks for all tree types, only called in usiblender.c, once ************ */
static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -3230,6 +3329,8 @@ void ED_node_init_butfuncs(void)
node_composit_set_butfunc(ntype);
node_shader_set_butfunc(ntype);
node_texture_set_butfunc(ntype);
+ node_simulation_set_butfunc(ntype);
+ node_function_set_butfunc(ntype);
/* define update callbacks for socket properties */
node_template_properties_update(ntype);
@@ -3240,6 +3341,7 @@ void ED_node_init_butfuncs(void)
ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING;
ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL;
ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE;
+ ntreeType_Simulation->ui_icon = ICON_PHYSICS; /* TODO: Use correct icon. */
}
void ED_init_custom_node_type(bNodeType *ntype)
@@ -3268,6 +3370,12 @@ static const float std_node_socket_colors[][4] = {
{0.0, 0.0, 0.0, 1.0}, /*__SOCK_MESH (deprecated) */
{0.06, 0.52, 0.15, 1.0}, /* SOCK_INT */
{0.39, 0.39, 0.39, 1.0}, /* SOCK_STRING */
+ {0.40, 0.10, 0.10, 1.0}, /* SOCK_OBJECT */
+ {0.10, 0.40, 0.10, 1.0}, /* SOCK_IMAGE */
+ {0.80, 0.80, 0.20, 1.0}, /* SOCK_EMITTERS */
+ {0.80, 0.20, 0.80, 1.0}, /* SOCK_EVENTS */
+ {0.20, 0.80, 0.80, 1.0}, /* SOCK_FORCES */
+ {0.30, 0.30, 0.30, 1.0}, /* SOCK_CONTROL_FLOW */
};
/* common color callbacks for standard types */
@@ -3362,7 +3470,7 @@ static void std_node_socket_draw(
case SOCK_FLOAT:
case SOCK_INT:
case SOCK_BOOLEAN:
- uiItemR(layout, ptr, "default_value", 0, text, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
break;
case SOCK_VECTOR:
if (sock->flag & SOCK_COMPACT) {
@@ -3370,11 +3478,11 @@ static void std_node_socket_draw(
}
else {
if (sock->typeinfo->subtype == PROP_DIRECTION) {
- uiItemR(layout, ptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
}
else {
uiLayout *column = uiLayoutColumn(layout, true);
- uiItemR(column, ptr, "default_value", 0, text, ICON_NONE);
+ uiItemR(column, ptr, "default_value", DEFAULT_FLAGS, text, ICON_NONE);
}
}
break;
@@ -3382,7 +3490,15 @@ static void std_node_socket_draw(
case SOCK_STRING: {
uiLayout *row = uiLayoutSplit(layout, 0.5f, false);
uiItemL(row, text, 0);
- uiItemR(row, ptr, "default_value", 0, "", 0);
+ uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
+ break;
+ }
+ case SOCK_OBJECT: {
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
+ break;
+ }
+ case SOCK_IMAGE: {
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
break;
}
default:
@@ -3400,32 +3516,32 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout
switch (type) {
case SOCK_FLOAT: {
uiLayout *row;
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0);
- uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
+ uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0);
+ uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0);
break;
}
case SOCK_INT: {
uiLayout *row;
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0);
- uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
+ uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0);
+ uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0);
break;
}
case SOCK_VECTOR: {
uiLayout *row;
- uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, NULL, 0);
+ uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, NULL, DEFAULT_FLAGS);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0);
- uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
+ uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0);
+ uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0);
break;
}
case SOCK_BOOLEAN:
case SOCK_RGBA:
case SOCK_STRING: {
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0);
break;
}
}
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index 4cf67dddb57..8fc343a9ed4 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -84,7 +84,7 @@ static void node_sockets_panel(const bContext *C, Panel *panel)
split = uiLayoutSplit(layout, 0.35f, false);
uiItemL(split, name, ICON_NONE);
- uiTemplateNodeLink(split, ntree, node, sock);
+ uiTemplateNodeLink(split, (bContext *)C, ntree, node, sock);
}
}
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 0552660b9bf..bd8950c5085 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -94,23 +94,11 @@ void ED_node_tree_update(const bContext *C)
static bNodeTree *node_tree_from_ID(ID *id)
{
if (id) {
- short idtype = GS(id->name);
-
- switch (idtype) {
- case ID_NT:
- return (bNodeTree *)id;
- case ID_MA:
- return ((Material *)id)->nodetree;
- case ID_LA:
- return ((Light *)id)->nodetree;
- case ID_WO:
- return ((World *)id)->nodetree;
- case ID_SCE:
- return ((Scene *)id)->nodetree;
- case ID_TE:
- return ((Tex *)id)->nodetree;
- case ID_LS:
- return ((FreestyleLineStyle *)id)->nodetree;
+ if (GS(id->name) == ID_NT) {
+ return (bNodeTree *)id;
+ }
+ else {
+ return ntreeFromID(id);
}
}
@@ -719,39 +707,19 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
#define MARKER_SHAPE_CIRCLE 0x2
#define MARKER_SHAPE_INNER_DOT 0x10
-static void node_socket_draw(const bContext *C,
- bNodeTree *ntree,
- PointerRNA node_ptr,
- bNodeSocket *sock,
+static void node_socket_draw(const bNodeSocket *sock,
+ const float color[4],
+ const float color_outline[4],
+ float size,
+ int locx,
+ int locy,
uint pos_id,
uint col_id,
uint shape_id,
uint size_id,
- uint outline_col_id,
- float size,
- bool selected)
+ uint outline_col_id)
{
- PointerRNA ptr;
- float color[4];
- float outline_color[4];
- uint flags = 0;
-
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
- sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color);
-
- bNode *node = node_ptr.data;
- if (node->flag & NODE_MUTED) {
- color[3] *= 0.25f;
- }
-
- if (selected) {
- UI_GetThemeColor4fv(TH_TEXT_HI, outline_color);
- outline_color[3] = 0.9f;
- }
- else {
- copy_v4_fl(outline_color, 0.0f);
- outline_color[3] = 0.6f;
- }
+ int flags;
/* sets shape flags */
switch (sock->display_shape) {
@@ -780,8 +748,120 @@ static void node_socket_draw(const bContext *C,
immAttr4fv(col_id, color);
immAttr1u(shape_id, flags);
immAttr1f(size_id, size);
- immAttr4fv(outline_col_id, outline_color);
- immVertex2f(pos_id, sock->locx, sock->locy);
+ immAttr4fv(outline_col_id, color_outline);
+ immVertex2f(pos_id, locx, locy);
+}
+
+static void node_socket_outline_color_get(bool selected, float r_outline_color[4])
+{
+ if (selected) {
+ UI_GetThemeColor4fv(TH_TEXT_HI, r_outline_color);
+ r_outline_color[3] = 0.9f;
+ }
+ else {
+ copy_v4_fl(r_outline_color, 0.0f);
+ r_outline_color[3] = 0.6f;
+ }
+}
+
+/* Usual convention here would be node_socket_get_color(), but that's already used (for setting a
+ * color property socket). */
+void node_socket_color_get(
+ bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4])
+{
+ PointerRNA ptr;
+
+ BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node));
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+
+ sock->typeinfo->draw_color(C, &ptr, node_ptr, r_color);
+
+ bNode *node = node_ptr->data;
+ if (node->flag & NODE_MUTED) {
+ r_color[3] *= 0.25f;
+ }
+}
+
+static void node_socket_draw_nested(const bContext *C,
+ bNodeTree *ntree,
+ PointerRNA *node_ptr,
+ bNodeSocket *sock,
+ uint pos_id,
+ uint col_id,
+ uint shape_id,
+ uint size_id,
+ uint outline_col_id,
+ float size,
+ bool selected)
+{
+ float color[4];
+ float outline_color[4];
+
+ node_socket_color_get((bContext *)C, ntree, node_ptr, sock, color);
+ node_socket_outline_color_get(selected, outline_color);
+
+ node_socket_draw(sock,
+ color,
+ outline_color,
+ size,
+ sock->locx,
+ sock->locy,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id);
+}
+
+/**
+ * Draw a single node socket at default size.
+ * \note this is only called from external code, internally #node_socket_draw_nested() is used for
+ * optimized drawing of multiple/all sockets of a node.
+ */
+void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
+{
+ const float size = 2.25f * NODE_SOCKSIZE * scale;
+ rcti draw_rect = *rect;
+ float outline_color[4] = {0};
+
+ node_socket_outline_color_get(sock->flag & SELECT, outline_color);
+
+ BLI_rcti_resize(&draw_rect, size, size);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint outline_col_id = GPU_vertformat_attr_add(
+ format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ gpuPushAttr(GPU_BLEND_BIT);
+ GPU_blend(true);
+ GPU_program_point_size(true);
+
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ immUniform1f("outline_scale", 0.7f);
+ immUniform2f("ViewportSize", -1.0f, -1.0f);
+
+ /* Single point */
+ immBegin(GPU_PRIM_POINTS, 1);
+ node_socket_draw(sock,
+ color,
+ outline_color,
+ BLI_rcti_size_y(&draw_rect),
+ BLI_rcti_cent_x(&draw_rect),
+ BLI_rcti_cent_y(&draw_rect),
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id);
+ immEnd();
+
+ immUnbindProgram();
+ GPU_program_point_size(false);
+ gpuPopAttr();
}
/* ************** Socket callbacks *********** */
@@ -974,17 +1054,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
}
/* socket outputs */
@@ -999,17 +1079,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
}
}
@@ -1032,17 +1112,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
if (--selected_input_len == 0) {
break; /* stop as soon as last one is drawn */
}
@@ -1057,17 +1137,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
if (--selected_output_len == 0) {
break; /* stop as soon as last one is drawn */
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index a82acfc4dbe..bd5ce135f82 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -69,6 +69,7 @@
#include "NOD_composite.h"
#include "NOD_shader.h"
+#include "NOD_simulation.h"
#include "NOD_texture.h"
#include "node_intern.h" /* own include */
@@ -438,6 +439,11 @@ bool ED_node_is_texture(struct SpaceNode *snode)
return STREQ(snode->tree_idname, ntreeType_Texture->idname);
}
+bool ED_node_is_simulation(struct SpaceNode *snode)
+{
+ return STREQ(snode->tree_idname, ntreeType_Simulation->idname);
+}
+
/* assumes nothing being done in ntree yet, sets the default in/out node */
/* called from shading buttons or header */
void ED_node_shader_default(const bContext *C, ID *id)
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 3a0ef45a68d..2617384d046 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -69,7 +69,8 @@ static bool node_group_operator_active(bContext *C)
*/
if (STREQ(snode->tree_idname, "ShaderNodeTree") ||
STREQ(snode->tree_idname, "CompositorNodeTree") ||
- STREQ(snode->tree_idname, "TextureNodeTree")) {
+ STREQ(snode->tree_idname, "TextureNodeTree") ||
+ STREQ(snode->tree_idname, "SimulationNodeTree")) {
return true;
}
}
@@ -85,7 +86,8 @@ static bool node_group_operator_editable(bContext *C)
* Disabled otherwise to allow pynodes define their own operators
* with same keymap.
*/
- if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode)) {
+ if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode) ||
+ ED_node_is_simulation(snode)) {
return true;
}
}
@@ -111,6 +113,9 @@ static const char *group_node_idname(bContext *C)
else if (ED_node_is_texture(snode)) {
return "TextureNodeGroup";
}
+ else if (ED_node_is_simulation(snode)) {
+ return "SimulationNodeGroup";
+ }
return "";
}
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 42439e88c96..04186c3a727 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -38,6 +38,7 @@ struct bContext;
struct bNode;
struct bNodeLink;
struct bNodeSocket;
+struct wmGizmoGroupType;
struct wmKeyConfig;
struct wmWindow;
@@ -77,6 +78,11 @@ void node_draw_sockets(struct View2D *v2d,
void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node);
int node_select_area_default(struct bNode *node, int x, int y);
int node_tweak_area_default(struct bNode *node, int x, int y);
+void node_socket_color_get(struct bContext *C,
+ struct bNodeTree *ntree,
+ struct PointerRNA *node_ptr,
+ struct bNodeSocket *sock,
+ float r_color[4]);
void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree);
void node_draw_nodetree(const struct bContext *C,
struct ARegion *region,
@@ -122,7 +128,7 @@ void NODE_OT_find_node(struct wmOperatorType *ot);
/* node_view.c */
int space_node_view_flag(struct bContext *C,
- SpaceNode *snode,
+ struct SpaceNode *snode,
ARegion *region,
const int node_flag,
const int smooth_viewtx);
@@ -196,7 +202,7 @@ void NODE_OT_detach(struct wmOperatorType *ot);
void NODE_OT_link_viewer(struct wmOperatorType *ot);
-void NODE_OT_insert_offset(wmOperatorType *ot);
+void NODE_OT_insert_offset(struct wmOperatorType *ot);
/* node_edit.c */
void snode_notify(struct bContext *C, struct SpaceNode *snode);
@@ -207,8 +213,8 @@ void snode_update(struct SpaceNode *snode, struct bNode *node);
bool composite_node_active(struct bContext *C);
bool composite_node_editable(struct bContext *C);
-int node_has_hidden_sockets(bNode *node);
-void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set);
+int node_has_hidden_sockets(struct bNode *node);
+void node_set_hidden_sockets(struct SpaceNode *snode, bNode *node, int set);
int node_render_changed_exec(bContext *, struct wmOperator *);
int node_find_indicated_socket(struct SpaceNode *snode,
struct bNode **nodep,
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 50c32da4b5a..547abaf8809 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -766,7 +766,10 @@ static int node_lasso_select_invoke(bContext *C, wmOperator *op, const wmEvent *
return WM_gesture_lasso_invoke(C, op, event);
}
-static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves, eSelectOp sel_op)
+static bool do_lasso_select_node(bContext *C,
+ const int mcoords[][2],
+ short mcoords_len,
+ eSelectOp sel_op)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node;
@@ -783,7 +786,7 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves
}
/* get rectangle from operator */
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* do actual selection */
for (node = snode->edittree->nodes.first; node; node = node->next) {
@@ -799,7 +802,7 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves
if (UI_view2d_view_to_region_clip(
&region->v2d, cent[0], cent[1], &screen_co[0], &screen_co[1]) &&
BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) {
+ BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) {
nodeSetSelected(node, select);
changed = true;
}
@@ -814,15 +817,15 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves
static int node_lasso_select_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- do_lasso_select_node(C, mcords, mcords_tot, sel_op);
+ do_lasso_select_node(C, mcoords, mcoords_len, sel_op);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 7d4095326f8..87b1f662b59 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -45,6 +45,7 @@
#include "UI_interface.h"
#include "ED_node.h" /* own include */
+#include "node_intern.h"
#include "ED_undo.h"
@@ -662,17 +663,23 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
}
-void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
+void uiTemplateNodeLink(
+ uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
{
uiBlock *block = uiLayoutGetBlock(layout);
NodeLinkArg *arg;
uiBut *but;
+ float socket_col[4];
arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
arg->ntree = ntree;
arg->node = node;
arg->sock = sock;
+ PointerRNA node_ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
+ node_socket_color_get(C, ntree, &node_ptr, sock, socket_col);
+
UI_block_layout_set_current(block, layout);
if (sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
@@ -687,8 +694,9 @@ void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSo
}
UI_but_type_set_menu_from_pulldown(but);
+ UI_but_node_link_set(but, sock, socket_col);
+ UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
- but->flag |= UI_BUT_NODE_LINK;
but->poin = (char *)but;
but->func_argN = arg;
@@ -708,18 +716,14 @@ static void ui_node_draw_node(
uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
{
bNodeSocket *input;
- uiLayout *col, *split;
PointerRNA nodeptr;
RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
if (node->typeinfo->draw_buttons) {
if (node->type != NODE_GROUP) {
- split = uiLayoutSplit(layout, 0.5f, false);
- col = uiLayoutColumn(split, false);
- col = uiLayoutColumn(split, false);
-
- node->typeinfo->draw_buttons(col, C, &nodeptr);
+ uiLayoutSetPropSep(layout, true);
+ node->typeinfo->draw_buttons(layout, C, &nodeptr);
}
}
@@ -733,12 +737,9 @@ static void ui_node_draw_input(
{
PointerRNA inputptr, nodeptr;
uiBlock *block = uiLayoutGetBlock(layout);
- uiBut *bt;
- uiLayout *split, *row, *col;
+ uiLayout *row = NULL;
bNode *lnode;
- char label[UI_MAX_NAME_STR];
- int i, indent = (depth > 1) ? 2 * (depth - 1) : 0;
- int dependency_loop;
+ bool dependency_loop;
if (input->flag & SOCK_UNAVAIL) {
return;
@@ -757,48 +758,43 @@ static void ui_node_draw_input(
RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
- /* indented label */
- for (i = 0; i < indent; i++) {
- label[i] = ' ';
- }
- label[indent] = '\0';
- BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name));
+ row = uiLayoutRow(layout, true);
+ /* Decorations are added manually here. */
+ uiLayoutSetPropDecorate(row, false);
- /* split in label and value */
- split = uiLayoutSplit(layout, 0.5f, false);
+ uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(row);
+ /* Empty decorator item for alignment. */
+ bool add_dummy_decorator = false;
- row = uiLayoutRow(split, true);
+ {
+ uiLayout *sub = uiLayoutRow(split_wrapper.label_column, true);
- if (depth > 0) {
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ if (depth > 0) {
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
- if (lnode &&
- (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) {
- int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT :
- ICON_DISCLOSURE_TRI_DOWN;
- uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
- }
- else {
- uiItemL(row, "", ICON_BLANK1);
- }
+ if (lnode &&
+ (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) {
+ int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT :
+ ICON_DISCLOSURE_TRI_DOWN;
+ uiItemR(sub, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
+ }
- bt = block->buttons.last;
- bt->rect.xmax = UI_UNIT_X / 2;
+ UI_block_emboss_set(block, UI_EMBOSS);
+ }
- UI_block_emboss_set(block, UI_EMBOSS);
+ sub = uiLayoutRow(sub, true);
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(sub, IFACE_(input->name), ICON_NONE);
}
- uiItemL(row, label, ICON_NONE);
- bt = block->buttons.last;
- bt->drawflag = UI_BUT_TEXT_RIGHT;
-
if (dependency_loop) {
- row = uiLayoutRow(split, false);
uiItemL(row, IFACE_("Dependency Loop"), ICON_ERROR);
+ add_dummy_decorator = true;
}
else if (lnode) {
/* input linked to a node */
- uiTemplateNodeLink(split, ntree, node, input);
+ uiTemplateNodeLink(row, C, ntree, node, input);
+ add_dummy_decorator = true;
if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
if (depth == 0) {
@@ -809,33 +805,41 @@ static void ui_node_draw_input(
}
}
else {
+ row = uiLayoutRow(row, true);
+
+ uiTemplateNodeLink(row, C, ntree, node, input);
+
+ if (input->flag & SOCK_HIDE_VALUE) {
+ add_dummy_decorator = true;
+ }
/* input not linked, show value */
- if (!(input->flag & SOCK_HIDE_VALUE)) {
+ else {
+ uiLayout *sub = row;
+
switch (input->type) {
+ case SOCK_VECTOR:
+ if (input->type == SOCK_VECTOR) {
+ uiItemS(row);
+ sub = uiLayoutColumn(row, true);
+ }
+ ATTR_FALLTHROUGH;
case SOCK_FLOAT:
case SOCK_INT:
case SOCK_BOOLEAN:
case SOCK_RGBA:
case SOCK_STRING:
- row = uiLayoutRow(split, true);
- uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE);
- break;
- case SOCK_VECTOR:
- row = uiLayoutRow(split, false);
- col = uiLayoutColumn(row, false);
- uiItemR(col, &inputptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
+ uiItemDecoratorR(
+ split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX);
break;
-
default:
- row = uiLayoutRow(split, false);
- break;
+ add_dummy_decorator = true;
}
}
- else {
- row = uiLayoutRow(split, false);
- }
+ }
- uiTemplateNodeLink(row, ntree, node, input);
+ if (add_dummy_decorator) {
+ uiItemDecoratorR(split_wrapper.decorate_column, NULL, NULL, 0);
}
/* clear */
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index b6ee393b991..30fe9a1ed11 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -938,6 +938,11 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
bool free;
const EnumPropertyItem *item_src = RNA_enum_node_tree_types_itemf_impl(C, &free);
for (const EnumPropertyItem *item_iter = item_src; item_iter->identifier; item_iter++) {
+#ifndef WITH_NEW_SIMULATION_TYPE
+ if (STREQ(item_iter->identifier, "SimulationNodeTree")) {
+ continue;
+ }
+#endif
RNA_enum_item_add(item, totitem, item_iter);
}
if (free) {
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index c77ee67b859..82ff9e06194 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -300,19 +300,15 @@ static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *c
return TRAVERSE_CONTINUE;
}
-static int collection_delete_exec(bContext *C, wmOperator *op)
+void outliner_collection_delete(
+ bContext *C, Main *bmain, Scene *scene, ReportList *reports, bool hierarchy)
{
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const Base *basact_prev = BASACT(view_layer);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
+
struct CollectionEditData data = {
.scene = scene,
.soops = soops,
};
- bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
data.collections_to_edit = BLI_gset_ptr_new(__func__);
@@ -358,7 +354,7 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
}
else {
BKE_reportf(
- op->reports,
+ reports,
RPT_WARNING,
"Cannot delete linked collection '%s', it is used by other linked scenes/collections",
collection->id.name + 2);
@@ -367,6 +363,17 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
}
BLI_gset_free(data.collections_to_edit, NULL);
+}
+
+static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ const Base *basact_prev = BASACT(view_layer);
+
+ outliner_collection_delete(C, bmain, scene, op->reports, true);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
@@ -382,24 +389,19 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void OUTLINER_OT_collection_delete(wmOperatorType *ot)
+void OUTLINER_OT_collection_hierarchy_delete(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete Collection";
- ot->idname = "OUTLINER_OT_collection_delete";
- ot->description = "Delete selected collections";
+ ot->name = "Delete Hierarchy";
+ ot->idname = "OUTLINER_OT_collection_hierarchy_delete";
+ ot->description = "Delete selected collection hierarchies";
/* api callbacks */
- ot->exec = collection_delete_exec;
+ ot->exec = collection_hierarchy_delete_exec;
ot->poll = ED_outliner_collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- PropertyRNA *prop = RNA_def_boolean(
- ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index ce83cfc3c97..6eba41982a7 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -2581,6 +2581,10 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case ID_PC:
data.icon = ICON_CURVE_BEZCURVE;
break;
+ case ID_SIM:
+ /* TODO: Use correct icon. */
+ data.icon = ICON_PHYSICS;
+ break;
default:
break;
}
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 469a0065e3a..8b4e38a77fd 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -83,9 +83,11 @@
#include "outliner_intern.h"
-/* ************************************************************** */
+/** \} */
-/* Highlight --------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Highlight on Cursor Motion Operator
+ * \{ */
static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
@@ -140,7 +142,11 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* Toggle Open/Closed ------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Open/Closed Operator
+ * \{ */
/* Open or close a tree element, optionally toggling all children recursively */
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
@@ -262,8 +268,10 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items");
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/** \name Object Mode Enter/Exit
+/** \name Object Mode Enter/Exit Utilities
* \{ */
static void item_object_mode_enter_exit(bContext *C, ReportList *reports, Object *ob, bool enter)
@@ -317,7 +325,9 @@ void item_object_mode_exit_cb(bContext *C,
/** \} */
-/* Rename --------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Rename Operator
+ * \{ */
static void do_item_rename(ARegion *region,
TreeElement *te,
@@ -449,7 +459,11 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* ID delete --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Delete Operator
+ * \{ */
static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
{
@@ -563,7 +577,11 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* ID remap --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Remap Operator
+ * \{ */
static int outliner_id_remap_exec(bContext *C, wmOperator *op)
{
@@ -736,7 +754,11 @@ void id_remap_cb(bContext *C,
WM_operator_properties_free(&op_props);
}
-/* ID copy/Paste ------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Copy Operator
+ * \{ */
static int outliner_id_copy_tag(SpaceOutliner *soops, ListBase *tree)
{
@@ -801,6 +823,12 @@ void OUTLINER_OT_id_copy(wmOperatorType *ot)
ot->flag = 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Paste Operator
+ * \{ */
+
static int outliner_id_paste_exec(bContext *C, wmOperator *op)
{
char str[FILE_MAX];
@@ -835,7 +863,11 @@ void OUTLINER_OT_id_paste(wmOperatorType *ot)
ot->flag = 0;
}
-/* Library relocate/reload --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library Relocate Operator
+ * \{ */
static int lib_relocate(
bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
@@ -979,6 +1011,12 @@ static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library Reload Operator
+ * \{ */
+
void OUTLINER_OT_lib_reload(wmOperatorType *ot)
{
ot->name = "Reload Library";
@@ -1002,13 +1040,11 @@ void lib_reload_cb(bContext *C,
lib_relocate(C, te, tselem, ot, true);
}
-/* ************************************************************** */
-/* Setting Toggling Operators */
-
-/* =============================================== */
-/* Toggling Utilities (Exported) */
+/** \} */
-/* Apply Settings ------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Apply Settings Utilities
+ * \{ */
static int outliner_count_levels(ListBase *lb, const int curlevel)
{
@@ -1090,7 +1126,11 @@ bool outliner_flag_flip(ListBase *lb, short flag)
return changed;
}
-/* Restriction Columns ------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Restriction Column Utility
+ * \{ */
/* same check needed for both object operation and restrict column button func
* return 0 when in edit mode (cannot restrict view or select)
@@ -1116,10 +1156,11 @@ int common_restrict_check(bContext *C, Object *ob)
return 1;
}
-/* =============================================== */
-/* Outliner setting toggles */
+/** \} */
-/* Toggle Expanded (Outliner) ---------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Toggle Expanded (Outliner) Operator
+ * \{ */
static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1152,7 +1193,11 @@ void OUTLINER_OT_expanded_toggle(wmOperatorType *ot)
/* no undo or registry, UI option */
}
-/* Toggle Selected (Outliner) ---------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Selected (Outliner) Operator
+ * \{ */
static int outliner_select_all_exec(bContext *C, wmOperator *op)
{
@@ -1202,10 +1247,11 @@ void OUTLINER_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-/* ************************************************************** */
-/* Hotkey Only Operators */
+/** \} */
-/* Show Active --------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name View Show Active (Outliner) Operator
+ * \{ */
static void outliner_set_coordinates_element_recursive(SpaceOutliner *soops,
TreeElement *te,
@@ -1355,7 +1401,11 @@ void OUTLINER_OT_show_active(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* View Panning --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Panning (Outliner) Operator
+ * \{ */
static int outliner_scroll_page_exec(bContext *C, wmOperator *op)
{
@@ -1393,10 +1443,14 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* Search ------------------------------------------------------- */
-// TODO: probably obsolete now with filtering?
+/** \} */
+
+#if 0 // TODO: probably obsolete now with filtering?
+
+/* -------------------------------------------------------------------- */
+/** \name Search
+ * \{ */
-#if 0
/* find next element that has this name */
static TreeElement *outliner_find_name(
@@ -1509,9 +1563,14 @@ static void outliner_find_panel(
BKE_reportf(reports, RPT_WARNING, "Not found: %s", name);
}
}
-#endif
-/* Show One Level ----------------------------------------------- */
+/** \} */
+
+#endif /* if 0 */
+
+/* -------------------------------------------------------------------- */
+/** \name Show One Level Operator
+ * \{ */
/* helper function for Show/Hide one level operator */
static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open)
@@ -1584,7 +1643,11 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* Show Hierarchy ----------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Show Hierarchy Operator
+ * \{ */
/* Helper function for tree_element_shwo_hierarchy() -
* recursively checks whether subtrees have any objects. */
@@ -1676,11 +1739,15 @@ void OUTLINER_OT_show_hierarchy(wmOperatorType *ot)
/* no undo or registry, UI option */
}
-/* ************************************************************** */
-/* ANIMATO OPERATIONS */
-/* KeyingSet and Driver Creation - Helper functions */
+/** \} */
-/* specialized poll callback for these operators to work in Datablocks view only */
+/* -------------------------------------------------------------------- */
+/** \name Animation Internal Utilities
+ * \{ */
+
+/**
+ * Specialized poll callback for these operators to work in data-blocks view only.
+ */
static bool ed_operator_outliner_datablocks_active(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -1842,19 +1909,23 @@ static void tree_element_to_path(TreeElement *te,
BLI_freelistN(&hierarchy);
}
-/* =============================================== */
-/* Driver Operations */
+/** \} */
-/* These operators are only available in databrowser mode for now, as
- * they depend on having RNA paths and/or hierarchies available.
+/* -------------------------------------------------------------------- */
+/** \name Driver Internal Utilities
+ * \{ */
+
+/**
+ * Driver Operations
+ *
+ * These operators are only available in data-browser mode for now,
+ * as they depend on having RNA paths and/or hierarchies available.
*/
enum {
DRIVERS_EDITMODE_ADD = 0,
DRIVERS_EDITMODE_REMOVE,
} /*eDrivers_EditModes*/;
-/* Utilities ---------------------------------- */
-
/* Recursively iterate over tree, finding and working on selected items */
static void do_outliner_drivers_editop(SpaceOutliner *soops,
ListBase *tree,
@@ -1930,7 +2001,11 @@ static void do_outliner_drivers_editop(SpaceOutliner *soops,
}
}
-/* Add Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Add Operator
+ * \{ */
static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
{
@@ -1965,7 +2040,11 @@ void OUTLINER_OT_drivers_add_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Remove Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Remove Operator
+ * \{ */
static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
{
@@ -2000,10 +2079,16 @@ void OUTLINER_OT_drivers_delete_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* =============================================== */
-/* Keying Set Operations */
+/** \} */
-/* These operators are only available in databrowser mode for now, as
+/* -------------------------------------------------------------------- */
+/** \name Keying-Set Internal Utilities
+ * \{ */
+
+/**
+ * Keying-Set Operations
+ *
+ * These operators are only available in data-browser mode for now, as
* they depend on having RNA paths and/or hierarchies available.
*/
enum {
@@ -2011,8 +2096,6 @@ enum {
KEYINGSET_EDITMODE_REMOVE,
} /*eKeyingSet_EditModes*/;
-/* Utilities ---------------------------------- */
-
/* find the 'active' KeyingSet, and add if not found (if adding is allowed) */
// TODO: should this be an API func?
static KeyingSet *verify_active_keyingset(Scene *scene, short add)
@@ -2104,7 +2187,11 @@ static void do_outliner_keyingset_editop(SpaceOutliner *soops,
}
}
-/* Add Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keying-Set Add Operator
+ * \{ */
static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
{
@@ -2145,7 +2232,11 @@ void OUTLINER_OT_keyingset_add_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Remove Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keying-Set Remove Operator
+ * \{ */
static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2182,8 +2273,11 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ************************************************************** */
-/* ORPHANED DATABLOCKS */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Purge Orphan Data-Blocks Operator
+ * \{ */
static bool ed_operator_outliner_id_orphans_active(bContext *C)
{
@@ -2195,7 +2289,7 @@ static bool ed_operator_outliner_id_orphans_active(bContext *C)
return true;
}
-/* Purge Orphans Operator --------------------------------------- */
+/** \} */
static void outliner_orphans_purge_tag(ID *id, int *num_tagged)
{
@@ -2313,3 +2407,5 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
+
+/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 90092817acc..f2b64bc2a4b 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -108,7 +108,8 @@ typedef struct TreeElementIcon {
ID_LP, \
ID_HA, \
ID_PT, \
- ID_VO) || /* Only in 'blendfile' mode ... :/ */ \
+ ID_VO, \
+ ID_SIM) || /* Only in 'blendfile' mode ... :/ */ \
ELEM(GS((_id)->name), \
ID_SCR, \
ID_WM, \
@@ -430,6 +431,7 @@ void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot);
void OUTLINER_OT_action_set(struct wmOperatorType *ot);
void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot);
void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_delete(struct wmOperatorType *ot);
/* ---------------------------------------------------------------- */
@@ -441,11 +443,16 @@ void outliner_keymap(struct wmKeyConfig *keyconf);
bool outliner_is_collection_tree_element(const TreeElement *te);
struct Collection *outliner_collection_from_tree_element(const TreeElement *te);
+void outliner_collection_delete(struct bContext *C,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct ReportList *reports,
+ bool hierarchy);
void OUTLINER_OT_collection_new(struct wmOperatorType *ot);
void OUTLINER_OT_collection_duplicate_linked(struct wmOperatorType *ot);
void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot);
-void OUTLINER_OT_collection_delete(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_hierarchy_delete(struct wmOperatorType *ot);
void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot);
void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot);
void OUTLINER_OT_collection_link(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 9d7efc7fe46..af7d97b6950 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -66,6 +66,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_action_set);
WM_operatortype_append(OUTLINER_OT_constraint_operation);
WM_operatortype_append(OUTLINER_OT_modifier_operation);
+ WM_operatortype_append(OUTLINER_OT_delete);
WM_operatortype_append(OUTLINER_OT_show_one_level);
WM_operatortype_append(OUTLINER_OT_show_active);
@@ -93,7 +94,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_collection_new);
WM_operatortype_append(OUTLINER_OT_collection_duplicate_linked);
WM_operatortype_append(OUTLINER_OT_collection_duplicate);
- WM_operatortype_append(OUTLINER_OT_collection_delete);
+ WM_operatortype_append(OUTLINER_OT_collection_hierarchy_delete);
WM_operatortype_append(OUTLINER_OT_collection_objects_select);
WM_operatortype_append(OUTLINER_OT_collection_objects_deselect);
WM_operatortype_append(OUTLINER_OT_collection_link);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 1c9998d256b..172d64c9c67 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -39,6 +39,7 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_volume_types.h"
#include "DNA_world_types.h"
@@ -88,9 +89,9 @@
#include "outliner_intern.h"
-/* ****************************************************** */
-
-/* ************ SELECTION OPERATIONS ********* */
+/* -------------------------------------------------------------------- */
+/** \name ID/Library/Data Set/Un-link Utilities
+ * \{ */
static void set_operation_types(SpaceOutliner *soops,
ListBase *lb,
@@ -160,6 +161,7 @@ static void set_operation_types(SpaceOutliner *soops,
case ID_HA:
case ID_PT:
case ID_VO:
+ case ID_SIM:
is_standard_id = true;
break;
case ID_WM:
@@ -412,7 +414,12 @@ static void outliner_do_libdata_operation(bContext *C,
}
}
-/* ******************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scene Menu Operator
+ * \{ */
+
typedef enum eOutliner_PropSceneOps {
OL_SCENE_OP_DELETE = 1,
} eOutliner_PropSceneOps;
@@ -500,7 +507,12 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", "");
}
-/* ******************************************** */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Search Utilities
+ * \{ */
/**
* Stores the parent and a child element of a merged icon-row icon for
@@ -641,6 +653,12 @@ static void object_select_cb(bContext *C,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks (Selection, Users & Library) Utilities
+ * \{ */
+
static void object_select_hierarchy_cb(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@@ -671,13 +689,10 @@ static void object_deselect_cb(bContext *C,
}
}
-static void object_delete_cb(bContext *C,
- ReportList *reports,
- Scene *scene,
- TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *UNUSED(user_data))
+static void outliner_object_delete(bContext *C,
+ ReportList *reports,
+ Scene *scene,
+ TreeStoreElem *tselem)
{
Object *ob = (Object *)tselem->id;
if (ob) {
@@ -883,7 +898,11 @@ void outliner_do_object_operation(bContext *C,
outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, NULL, true);
}
-/* ******************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Tagging Utilities
+ * \{ */
static void clear_animdata_cb(int UNUSED(event),
TreeElement *UNUSED(te),
@@ -935,7 +954,11 @@ static void refreshdrivers_animdata_cb(int UNUSED(event),
}
}
-/* --------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Operation Utilities
+ * \{ */
typedef enum eOutliner_PropDataOps {
OL_DOP_SELECT = 1,
@@ -1308,13 +1331,16 @@ static void object_batch_delete_hierarchy_cb(bContext *C,
}
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Menu Operator
+ * \{ */
enum {
OL_OP_SELECT = 1,
OL_OP_DESELECT,
OL_OP_SELECT_HIERARCHY,
- OL_OP_DELETE,
OL_OP_DELETE_HIERARCHY,
OL_OP_REMAP,
OL_OP_LOCALIZED, /* disabled, see below */
@@ -1330,7 +1356,6 @@ static const EnumPropertyItem prop_object_op_types[] = {
{OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""},
{OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
- {OL_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
{OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
{OL_OP_REMAP,
"REMAP",
@@ -1386,29 +1411,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Deselect Objects";
selection_changed = true;
}
- else if (event == OL_OP_DELETE) {
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const Base *basact_prev = BASACT(view_layer);
-
- outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb);
-
- /* XXX: tree management normally happens from draw_outliner(), but when
- * you're clicking to fast on Delete object from context menu in
- * outliner several mouse events can be handled in one cycle without
- * handling notifiers/redraw which leads to deleting the same object twice.
- * cleanup tree here to prevent such cases. */
- outliner_cleanup_tree(soops);
-
- DEG_relations_tag_update(bmain);
- str = "Delete Objects";
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- if (basact_prev != BASACT(view_layer)) {
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
- WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
- }
- selection_changed = true;
- }
else if (event == OL_OP_DELETE_HIERARCHY) {
ViewLayer *view_layer = CTX_data_view_layer(C);
const Base *basact_prev = BASACT(view_layer);
@@ -1433,7 +1435,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
BKE_id_multi_tagged_delete(bmain);
}
- /* XXX: See OL_OP_DELETE comment above. */
+ /* XXX: See outliner_delete_exec comment below. */
outliner_cleanup_tree(soops);
DEG_relations_tag_update(bmain);
@@ -1500,7 +1502,85 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", "");
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Object/Collection Operator
+ * \{ */
+
+static void outliner_objects_delete(
+ bContext *C, Scene *scene, SpaceOutliner *soops, ReportList *reports, ListBase *lb)
+{
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tselem->flag & TSE_SELECTED) {
+ if (tselem->type == 0 && te->idcode == ID_OB) {
+ outliner_object_delete(C, reports, scene, tselem);
+ }
+ }
+
+ if (TSELEM_OPEN(tselem, soops)) {
+ outliner_objects_delete(C, scene, soops, reports, &te->subtree);
+ }
+ }
+}
+
+static int outliner_delete_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceOutliner *soops = CTX_wm_space_outliner(C);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const Base *basact_prev = BASACT(view_layer);
+
+ outliner_collection_delete(C, bmain, scene, op->reports, false);
+ outliner_objects_delete(C, scene, soops, op->reports, &soops->tree);
+
+ /* Tree management normally happens from draw_outliner(), but when
+ * you're clicking too fast on Delete object from context menu in
+ * outliner several mouse events can be handled in one cycle without
+ * handling notifiers/redraw which leads to deleting the same object twice.
+ * cleanup tree here to prevent such cases. */
+ outliner_cleanup_tree(soops);
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+
+ if (basact_prev != BASACT(view_layer)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
+ }
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete";
+ ot->idname = "OUTLINER_OT_delete";
+ ot->description = "Delete selected objects and collections";
+
+ /* callbacks */
+ ot->exec = outliner_delete_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID-Data Menu Operator
+ * \{ */
typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_INVALID = 0,
@@ -1800,7 +1880,11 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
RNA_def_enum_funcs(ot->prop, outliner_id_operation_itemf);
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library Menu Operator
+ * \{ */
typedef enum eOutlinerLibOpTypes {
OL_LIB_INVALID = 0,
@@ -1901,7 +1985,11 @@ void OUTLINER_OT_lib_operation(wmOperatorType *ot)
ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", "");
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Outliner Set Active Action Operator
+ * \{ */
static void outliner_do_id_set_operation(
SpaceOutliner *soops,
@@ -1927,8 +2015,6 @@ static void outliner_do_id_set_operation(
}
}
-/* ------------------------------------------ */
-
static void actionset_id_cb(TreeElement *UNUSED(te),
TreeStoreElem *tselem,
TreeStoreElem *tsep,
@@ -2026,7 +2112,11 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
ot->prop = prop;
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Menu Operator
+ * \{ */
typedef enum eOutliner_AnimDataOps {
OUTLINER_ANIMOP_INVALID = 0,
@@ -2142,7 +2232,11 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", "");
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Constraint Menu Operator
+ * \{ */
static const EnumPropertyItem prop_constraint_op_types[] = {
{OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""},
@@ -2188,7 +2282,11 @@ void OUTLINER_OT_constraint_operation(wmOperatorType *ot)
ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", "");
}
-/* ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Modifier Menu Operator
+ * \{ */
static const EnumPropertyItem prop_modifier_op_types[] = {
{OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""},
@@ -2233,7 +2331,11 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", "");
}
-/* ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Data Menu Operator
+ * \{ */
// XXX: select linked is for RNA structs only
static const EnumPropertyItem prop_data_op_types[] = {
@@ -2326,7 +2428,11 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", "");
}
-/* ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Context Menu Operator
+ * \{ */
static int outliner_operator_menu(bContext *C, const char *opname)
{
@@ -2491,4 +2597,4 @@ void OUTLINER_OT_operation(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* ****************************************************** */
+/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index b226d291188..7bb62b0d1e2 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -46,6 +46,7 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_speaker_types.h"
#include "DNA_volume_types.h"
#include "DNA_world_types.h"
@@ -58,7 +59,7 @@
#include "BLT_translation.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_idtype.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
@@ -773,6 +774,13 @@ static void outliner_add_id_contents(SpaceOutliner *soops,
outliner_add_element(soops, &te->subtree, volume, te, TSE_ANIM_DATA, 0);
break;
}
+ case ID_SIM: {
+ Simulation *simulation = (Simulation *)id;
+ if (outliner_animdata_test(simulation->adt)) {
+ outliner_add_element(soops, &te->subtree, simulation, te, TSE_ANIM_DATA, 0);
+ }
+ break;
+ }
default:
break;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index b06bc7ad8b7..243a6e193eb 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -447,7 +447,6 @@ static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col)
typedef struct MakeHistogramViewData {
const ImBuf *ibuf;
- uint32_t (*bins)[HIS_STEPS];
} MakeHistogramViewData;
static void make_histogram_view_from_ibuf_byte_fn(void *__restrict userdata,
@@ -469,17 +468,16 @@ static void make_histogram_view_from_ibuf_byte_fn(void *__restrict userdata,
}
}
-static void make_histogram_view_from_ibuf_finalize(void *__restrict userdata,
- void *__restrict userdata_chunk)
+static void make_histogram_view_from_ibuf_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- MakeHistogramViewData *data = userdata;
- uint32_t(*bins)[HIS_STEPS] = data->bins;
-
- uint32_t(*cur_bins)[HIS_STEPS] = userdata_chunk;
+ uint32_t(*join_bins)[HIS_STEPS] = chunk_join;
+ uint32_t(*bins)[HIS_STEPS] = chunk;
for (int j = 3; j--;) {
for (int i = 0; i < HIS_STEPS; i++) {
- bins[j][i] += cur_bins[j][i];
+ join_bins[j][i] += bins[j][i];
}
}
}
@@ -496,14 +494,13 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
MakeHistogramViewData data = {
.ibuf = ibuf,
- .bins = bins,
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (ibuf->y >= 256);
settings.userdata_chunk = bins;
settings.userdata_chunk_size = sizeof(bins);
- settings.func_finalize = make_histogram_view_from_ibuf_finalize;
+ settings.func_reduce = make_histogram_view_from_ibuf_reduce;
BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_byte_fn, &settings);
nr = nb = ng = 0;
@@ -582,14 +579,13 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
MakeHistogramViewData data = {
.ibuf = ibuf,
- .bins = bins,
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (ibuf->y >= 256);
settings.userdata_chunk = bins;
settings.userdata_chunk_size = sizeof(bins);
- settings.func_finalize = make_histogram_view_from_ibuf_finalize;
+ settings.func_reduce = make_histogram_view_from_ibuf_reduce;
BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_float_fn, &settings);
nr = nb = ng = 0;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index e58559f4f6b..fac378ae104 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -63,6 +63,7 @@
#include "ED_armature.h"
#include "ED_gpencil.h"
+#include "ED_info.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_screen_types.h"
@@ -101,6 +102,8 @@
#define M_GOLDEN_RATIO_CONJUGATE 0.618033988749895f
+#define VIEW3D_OVERLAY_LINEHEIGHT (0.9f * U.widget_unit)
+
/* -------------------------------------------------------------------- */
/** \name General Functions
* \{ */
@@ -1341,7 +1344,7 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y
UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
BLF_draw_default(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr));
@@ -1473,7 +1476,7 @@ static void draw_selected_name(
BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
BLF_shadow_offset(font_id, 1, -1);
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info));
BLF_disable(font_id, BLF_SHADOW);
@@ -1494,7 +1497,7 @@ static void draw_grid_unit_name(
BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid);
}
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
BLF_enable(font_id, BLF_SHADOW);
BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
BLF_shadow_offset(font_id, 1, -1);
@@ -1515,6 +1518,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
#ifdef WITH_INPUT_NDOF
if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) &&
@@ -1550,8 +1555,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
}
}
- int xoffset = rect->xmin + U.widget_unit;
- int yoffset = rect->ymax;
+ int xoffset = rect->xmin + (0.5f * U.widget_unit);
+ int yoffset = rect->ymax - (0.1f * U.widget_unit);
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
@@ -1562,7 +1567,6 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
}
if (U.uiflag & USER_DRAWVIEWINFO) {
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
draw_selected_name(scene, view_layer, ob, xoffset, &yoffset);
}
@@ -1571,10 +1575,12 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
/* draw below the viewport name */
draw_grid_unit_name(scene, rv3d, v3d, xoffset, &yoffset);
}
+
+ DRW_draw_region_engine_info(xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT);
}
- if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
- DRW_draw_region_engine_info(xoffset, yoffset);
+ if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_STATS)) {
+ ED_info_draw_stats(bmain, scene, view_layer, xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT);
}
BLF_batch_draw_end();
@@ -2493,7 +2499,7 @@ void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset)
BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
BLF_shadow_offset(font_id, 1, -1);
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
#ifdef WITH_INTERNATIONAL
BLF_draw_default(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 0a272db1344..97e7cf32a41 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -408,8 +408,8 @@ typedef struct LassoSelectUserData {
const rcti *rect;
const rctf *rect_fl;
rctf _rect_fl;
- const int (*mcords)[2];
- int moves;
+ const int (*mcoords)[2];
+ int mcoords_len;
eSelectOp sel_op;
/* runtime */
@@ -421,8 +421,8 @@ typedef struct LassoSelectUserData {
static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
ViewContext *vc,
const rcti *rect,
- const int (*mcords)[2],
- const int moves,
+ const int (*mcoords)[2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
r_data->vc = vc;
@@ -431,8 +431,8 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
r_data->rect_fl = &r_data->_rect_fl;
BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
- r_data->mcords = mcords;
- r_data->moves = moves;
+ r_data->mcoords = mcoords;
+ r_data->mcoords_len = mcoords_len;
r_data->sel_op = sel_op;
/* runtime */
@@ -527,7 +527,8 @@ static void do_lasso_select_pose__do_tag(void *userData,
if (screen_co_a[0] != IS_CLIPPED) {
points_proj_tot++;
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
is_point_done = true;
}
}
@@ -536,22 +537,28 @@ static void do_lasso_select_pose__do_tag(void *userData,
if (screen_co_b[0] != IS_CLIPPED) {
points_proj_tot++;
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
is_point_done = true;
}
}
/* if one of points selected, we skip the bone itself */
- if ((is_point_done == true) ||
- ((is_point_done == false) && (points_proj_tot == 2) &&
- BLI_lasso_is_edge_inside(
- data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX))) {
+ if ((is_point_done == true) || ((is_point_done == false) && (points_proj_tot == 2) &&
+ BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
+ UNPACK2(screen_co_a),
+ UNPACK2(screen_co_b),
+ INT_MAX))) {
pchan->bone->flag |= BONE_DONE;
}
data->is_changed |= is_point_done;
}
}
-static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves)
+static void do_lasso_tag_pose(ViewContext *vc,
+ Object *ob,
+ const int mcoords[][2],
+ short mcoords_len)
{
ViewContext vc_tmp;
LassoSelectUserData data;
@@ -564,9 +571,9 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2]
vc_tmp = *vc;
vc_tmp.obact = ob;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, 0);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, 0);
ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d);
@@ -574,8 +581,8 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2]
}
static bool do_lasso_select_objects(ViewContext *vc,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const short mcoords_len,
const eSelectOp sel_op)
{
View3D *v3d = vc->v3d;
@@ -591,7 +598,7 @@ static bool do_lasso_select_objects(ViewContext *vc,
const bool is_select = base->flag & BASE_SELECTED;
const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) &&
BLI_lasso_is_point_inside(
- mcords, moves, base->sx, base->sy, IS_CLIPPED));
+ mcoords, mcoords_len, base->sx, base->sy, IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
@@ -685,8 +692,8 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const
}
static bool do_lasso_select_pose(ViewContext *vc,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const short mcoords_len,
const eSelectOp sel_op)
{
uint bases_len;
@@ -695,7 +702,7 @@ static bool do_lasso_select_pose(ViewContext *vc,
for (int i = 0; i < bases_len; i++) {
Base *base_iter = bases[i];
Object *ob_iter = base_iter->object;
- do_lasso_tag_pose(vc, ob_iter, mcords, moves);
+ do_lasso_tag_pose(vc, ob_iter, mcoords, mcoords_len);
}
const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op);
@@ -715,9 +722,10 @@ static void do_lasso_select_mesh__doSelectVert(void *userData,
{
LassoSelectUserData *data = userData;
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
@@ -746,8 +754,10 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data,
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside =
(is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED));
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
@@ -770,8 +780,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data,
}
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
- const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcords,
- data->moves,
+ const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
UNPACK2(screen_co_a),
UNPACK2(screen_co_b),
IS_CLIPPED));
@@ -789,9 +799,10 @@ static void do_lasso_select_mesh__doSelectFace(void *userData,
{
LassoSelectUserData *data = userData;
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
@@ -801,8 +812,8 @@ static void do_lasso_select_mesh__doSelectFace(void *userData,
static bool do_lasso_select_mesh(ViewContext *vc,
wmGenericUserData *wm_userdata,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ short mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
@@ -812,9 +823,9 @@ static bool do_lasso_select_mesh(ViewContext *vc,
/* set editmesh */
vc->em = BKE_editmesh_from_object(vc->obedit);
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
if (vc->em->bm->totvertsel) {
@@ -836,7 +847,7 @@ static bool do_lasso_select_mesh(ViewContext *vc,
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
esel = wm_userdata->data;
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
}
}
@@ -897,7 +908,7 @@ static void do_lasso_select_curve__doSelect(void *userData,
LassoSelectUserData *data = userData;
const bool is_inside = BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED);
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED);
if (bp) {
const bool is_select = bp->f1 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
@@ -930,16 +941,16 @@ static void do_lasso_select_curve__doSelect(void *userData,
}
static bool do_lasso_select_curve(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ short mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
Curve *curve = (Curve *)vc->obedit->data;
@@ -958,9 +969,10 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const
{
LassoSelectUserData *data = userData;
const bool is_select = bp->f1 & SELECT;
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
@@ -968,16 +980,16 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const
}
}
static bool do_lasso_select_lattice(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ short mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
@@ -1002,7 +1014,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (screen_co_a[0] != IS_CLIPPED) {
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
is_inside_flag |= BONESEL_ROOT;
}
}
@@ -1012,7 +1025,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (screen_co_b[0] != IS_CLIPPED) {
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
is_inside_flag |= BONESEL_TIP;
}
}
@@ -1022,8 +1036,11 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (is_ignore_flag == 0) {
if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) ||
- BLI_lasso_is_edge_inside(
- data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
+ BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
+ UNPACK2(screen_co_a),
+ UNPACK2(screen_co_b),
+ INT_MAX)) {
is_inside_flag |= BONESEL_BONE;
}
}
@@ -1033,16 +1050,16 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
}
static bool do_lasso_select_armature(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ short mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit);
@@ -1071,9 +1088,10 @@ static void do_lasso_select_mball__doSelectElem(void *userData,
{
LassoSelectUserData *data = userData;
const bool is_select = ml->flag & SELECT;
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], INT_MAX));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT);
@@ -1081,8 +1099,8 @@ static void do_lasso_select_mball__doSelectElem(void *userData,
}
}
static bool do_lasso_select_meta(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ short mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
@@ -1090,9 +1108,9 @@ static bool do_lasso_select_meta(ViewContext *vc,
MetaBall *mb = (MetaBall *)vc->obedit->data;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= BKE_mball_deselect_all(mb);
@@ -1113,9 +1131,10 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData,
{
LassoSelectUserData *data = userData;
const bool is_select = mv->flag & SELECT;
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
@@ -1124,8 +1143,8 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData,
}
static bool do_lasso_select_paintvert(ViewContext *vc,
wmGenericUserData *wm_userdata,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ short mcoords_len,
const eSelectOp sel_op)
{
const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
@@ -1143,7 +1162,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
}
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
struct EditSelectBuf_Cache *esel = wm_userdata->data;
if (use_zbuf) {
@@ -1151,7 +1170,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX);
esel = wm_userdata->data;
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
}
}
@@ -1163,7 +1182,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
else {
LassoSelectUserData data;
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
@@ -1185,8 +1204,8 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
}
static bool do_lasso_select_paintface(ViewContext *vc,
wmGenericUserData *wm_userdata,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ short mcoords_len,
const eSelectOp sel_op)
{
Object *ob = vc->obact;
@@ -1203,14 +1222,14 @@ static bool do_lasso_select_paintface(ViewContext *vc,
changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false);
}
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
struct EditSelectBuf_Cache *esel = wm_userdata->data;
if (esel == NULL) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE);
esel = wm_userdata->data;
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
}
if (esel->select_bitmap) {
@@ -1224,7 +1243,7 @@ static bool do_lasso_select_paintface(ViewContext *vc,
}
#if 0
-static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp sel_op)
+static void do_lasso_select_node(int mcoords[][2], short mcoords_len, const eSelectOp sel_op)
{
SpaceNode *snode = area->spacedata.first;
@@ -1234,7 +1253,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s
float node_centf[2];
bool changed = false;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* store selection in temp test flag */
for (node = snode->edittree->nodes.first; node; node = node->next) {
@@ -1244,7 +1263,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s
ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
const bool is_select = node->flag & SELECT;
const bool is_inside = (BLI_rcti_isect_pt_v(&rect, node_cent) &&
- BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1]));
+ BLI_lasso_is_point_inside(mcoords, mcoords_len, node_cent[0], node_cent[1]));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT);
@@ -1257,8 +1276,11 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s
}
#endif
-static bool view3d_lasso_select(
- bContext *C, ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op)
+static bool view3d_lasso_select(bContext *C,
+ ViewContext *vc,
+ const int mcoords[][2],
+ short mcoords_len,
+ const eSelectOp sel_op)
{
Object *ob = CTX_data_active_object(C);
bool changed_multi = false;
@@ -1268,26 +1290,26 @@ static bool view3d_lasso_select(
if (vc->obedit == NULL) { /* Object Mode */
if (BKE_paint_select_face_test(ob)) {
- changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcoords, mcoords_len, sel_op);
}
else if (BKE_paint_select_vert_test(ob)) {
- changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcoords, mcoords_len, sel_op);
}
else if (ob &&
(ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
/* pass */
}
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
- changed_multi |= PE_lasso_select(C, mcords, moves, sel_op);
+ changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- changed_multi |= do_lasso_select_pose(vc, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_pose(vc, mcoords, mcoords_len, sel_op);
if (changed_multi) {
ED_outliner_select_sync_from_pose_bone_tag(C);
}
}
else {
- changed_multi |= do_lasso_select_objects(vc, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op);
if (changed_multi) {
ED_outliner_select_sync_from_object_tag(C);
}
@@ -1300,23 +1322,23 @@ static bool view3d_lasso_select(
switch (vc->obedit->type) {
case OB_MESH:
- changed = do_lasso_select_mesh(vc, wm_userdata, mcords, moves, sel_op);
+ changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op);
break;
case OB_CURVE:
case OB_SURF:
- changed = do_lasso_select_curve(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_curve(vc, mcoords, mcoords_len, sel_op);
break;
case OB_LATTICE:
- changed = do_lasso_select_lattice(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_lattice(vc, mcoords, mcoords_len, sel_op);
break;
case OB_ARMATURE:
- changed = do_lasso_select_armature(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_armature(vc, mcoords, mcoords_len, sel_op);
if (changed) {
ED_outliner_select_sync_from_edit_bone_tag(C);
}
break;
case OB_MBALL:
- changed = do_lasso_select_meta(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_meta(vc, mcoords, mcoords_len, sel_op);
break;
default:
BLI_assert(!"lasso select on incorrect object type");
@@ -1342,10 +1364,10 @@ static bool view3d_lasso_select(
static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
{
ViewContext vc;
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
@@ -1354,9 +1376,9 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- bool changed_multi = view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op);
+ bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
if (changed_multi) {
return OPERATOR_FINISHED;
@@ -1971,7 +1993,7 @@ static bool ed_object_select_pick(bContext *C,
/* setup view context for argument to callbacks */
ED_view3d_viewcontext_init(C, &vc, depsgraph);
- ARegion *region = CTX_wm_region(C);
+ const ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index d376c71d867..f3306caa931 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -778,9 +778,10 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
return keymap;
}
-static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane)
+static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is_plane)
{
if (!(t->flag & T_NO_CONSTRAINT)) {
+ char cmode = constraintModeToChar(t);
int constraint_axis, constraint_plane;
const bool edit_2d = (t->flag & T_2D_EDIT) != 0;
const char *msg1 = "", *msg2 = "", *msg3 = "";
@@ -824,34 +825,22 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
}
}
else if (!edit_2d) {
- if (cmode != axis) {
- /* First press, constraint to an axis. */
- t->orientation.index = 0;
- const short *orientation_ptr = t->orientation.types[t->orientation.index];
- const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
- if (is_plane == false) {
- setUserConstraint(t, orientation, constraint_axis, msg2);
- }
- else {
- setUserConstraint(t, orientation, constraint_plane, msg3);
- }
- }
- else {
+ if (ELEM(cmode, '\0', axis)) {
/* Successive presses on existing axis, cycle orientation modes. */
t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types);
+ initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]);
+ }
- if (t->orientation.index == 0) {
- stopConstraint(t);
+ if (t->orientation.index == 0) {
+ stopConstraint(t);
+ }
+ else {
+ const short orientation = t->orientation.types[t->orientation.index];
+ if (is_plane == false) {
+ setUserConstraint(t, orientation, constraint_axis, msg2);
}
else {
- const short *orientation_ptr = t->orientation.types[t->orientation.index];
- const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
- if (is_plane == false) {
- setUserConstraint(t, orientation, constraint_axis, msg2);
- }
- else {
- setUserConstraint(t, orientation, constraint_plane, msg3);
- }
+ setUserConstraint(t, orientation, constraint_plane, msg3);
}
}
}
@@ -861,7 +850,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
int transformEvent(TransInfo *t, const wmEvent *event)
{
- char cmode = constraintModeToChar(t);
bool handled = false;
const int modifiers_prev = t->modifiers;
const int mode_prev = t->mode;
@@ -1047,42 +1035,42 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_AXIS_X:
if (!(t->flag & T_NO_CONSTRAINT)) {
- transform_event_xyz_constraint(t, EVT_XKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_XKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_AXIS_Y:
if ((t->flag & T_NO_CONSTRAINT) == 0) {
- transform_event_xyz_constraint(t, EVT_YKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_YKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_AXIS_Z:
if ((t->flag & (T_NO_CONSTRAINT)) == 0) {
- transform_event_xyz_constraint(t, EVT_ZKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_ZKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_X:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, EVT_XKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_XKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_Y:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, EVT_YKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_YKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_Z:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, EVT_ZKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_ZKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
@@ -1228,17 +1216,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
stopConstraint(t);
}
else {
- if (event->shift) {
- /* bit hackish... but it prevents mmb select to print the
- * orientation from menu */
- float mati[3][3];
- strcpy(t->spacename, "global");
- unit_m3(mati);
- initSelectConstraint(t, mati);
- }
- else {
- initSelectConstraint(t, t->spacemtx);
- }
+ initSelectConstraint(t, event->shift);
postSelectConstraint(t);
}
}
@@ -1699,18 +1677,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
ts->prop_mode = t->prop_mode;
}
}
-
- if (t->spacetype == SPACE_VIEW3D) {
- if ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
- !RNA_property_is_set(op->ptr, prop) &&
- (t->orientation.user != V3D_ORIENT_CUSTOM_MATRIX)) {
- TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
- orient_slot->type = t->orientation.user;
- BLI_assert(((orient_slot->index_custom == -1) && (t->orientation.custom == NULL)) ||
- (BKE_scene_transform_orientation_get_index(t->scene, t->orientation.custom) ==
- orient_slot->index_custom));
- }
- }
}
if (t->flag & T_MODAL) {
@@ -1737,34 +1703,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0);
}
- /* Orientation used for redo. */
- const bool use_orient_axis = (t->orient_matrix_is_set &&
- (RNA_struct_find_property(op->ptr, "orient_axis") != NULL));
- short orientation;
- if (t->con.mode & CON_APPLY) {
- orientation = t->con.orientation;
- if (orientation == V3D_ORIENT_CUSTOM) {
- const int orientation_index_custom = BKE_scene_transform_orientation_get_index(
- t->scene, t->orientation.custom);
- /* Maybe we need a t->con.custom_orientation?
- * Seems like it would always match t->orientation.custom. */
- orientation = V3D_ORIENT_CUSTOM + orientation_index_custom;
- BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
- }
- }
- else if ((t->orientation.user == V3D_ORIENT_CUSTOM_MATRIX) &&
- (prop = RNA_struct_find_property(op->ptr, "orient_matrix_type"))) {
- orientation = RNA_property_enum_get(op->ptr, prop);
- }
- else if (use_orient_axis) {
- /* We're not using an orientation, use the fallback. */
- orientation = t->orientation.unset;
- }
- else {
- orientation = V3D_ORIENT_GLOBAL;
- unit_m3(t->spacemtx);
- }
-
if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
if (t->flag & T_MODAL) {
if (t->con.mode & CON_APPLY) {
@@ -1784,42 +1722,31 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix"))) {
- if (t->flag & T_MODAL) {
- if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
- if (t->flag & T_MODAL) {
- RNA_enum_set(op->ptr, "orient_matrix_type", orientation);
- }
- }
- if (t->con.mode & CON_APPLY) {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->con.mtx[0][0]);
- }
- else if (use_orient_axis) {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->orient_matrix[0][0]);
- }
- else {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
- }
+ if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) {
+ short orient_set, orient_cur;
+ orient_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : -1;
+ orient_cur = t->orientation.types[t->orientation.index];
+
+ if (!ELEM(orient_cur, orient_set, V3D_ORIENT_CUSTOM_MATRIX)) {
+ RNA_property_enum_set(op->ptr, prop, orient_cur);
+ orient_set = orient_cur;
}
- }
- if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) {
- /* constraint orientation can be global, even if user selects something else
- * so use the orientation in the constraint if set */
+ if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+ !RNA_property_is_set(op->ptr, prop))) {
+ /* Set the first time to register on redo. */
+ RNA_property_enum_set(op->ptr, prop, orient_set);
- /* Use 'orient_matrix' instead. */
- if (t->flag & T_MODAL) {
- if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
- RNA_property_enum_set(op->ptr, prop, orientation);
+ if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
+ !RNA_property_is_set(op->ptr, prop))) {
+ RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
}
}
}
if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
bool constraint_axis[3] = {false, false, false};
- if (t->flag & T_MODAL) {
- /* Only set if needed, so we can hide in the UI when nothing is set.
- * See 'transform_poll_property'. */
+ if (t->idx_max == 0) {
if (t->con.mode & CON_APPLY) {
if (t->con.mode & CON_AXIS0) {
constraint_axis[0] = true;
@@ -1830,10 +1757,17 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
if (t->con.mode & CON_AXIS2) {
constraint_axis[2] = true;
}
- }
- if (ELEM(true, UNPACK3(constraint_axis))) {
RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
}
+ else {
+ RNA_property_unset(op->ptr, prop);
+ }
+ }
+ else {
+ constraint_axis[0] = true;
+ constraint_axis[1] = true;
+ constraint_axis[2] = true;
+ RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
}
}
@@ -1959,7 +1893,13 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
unit_m3(t->spacemtx);
initTransInfo(C, t, op, event);
- initTransformOrientation(C, t);
+
+ /* Use the custom orientation when it is set. */
+ short orientation = t->orientation.types[0] == V3D_ORIENT_CUSTOM_MATRIX ?
+ V3D_ORIENT_CUSTOM_MATRIX :
+ t->orientation.types[t->orientation.index];
+
+ initTransformOrientation(C, t, orientation);
if (t->spacetype == SPACE_VIEW3D) {
t->draw_handle_apply = ED_region_draw_cb_activate(
@@ -2141,38 +2081,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Constraint init from operator */
- if ((t->flag & T_MODAL) ||
- /* For mirror operator the constraint axes are effectively the values. */
- (RNA_struct_find_property(op->ptr, "value") == NULL)) {
- if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) &&
- RNA_property_is_set(op->ptr, prop)) {
- bool constraint_axis[3];
-
- RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
-
- if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
- t->con.mode |= CON_APPLY;
-
- if (constraint_axis[0]) {
- t->con.mode |= CON_AXIS0;
- }
- if (constraint_axis[1]) {
- t->con.mode |= CON_AXIS1;
- }
- if (constraint_axis[2]) {
- t->con.mode |= CON_AXIS2;
- }
-
- setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
- }
- }
- }
- else {
- /* So we can adjust in non global orientation. */
- if (t->orientation.user != V3D_ORIENT_GLOBAL) {
- t->con.mode |= CON_APPLY | CON_AXIS0 | CON_AXIS1 | CON_AXIS2;
- setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
- }
+ if (t->con.mode & CON_APPLY) {
+ setUserConstraint(t, t->orientation.types[t->orientation.index], t->con.mode, "%s");
}
/* Don't write into the values when non-modal because they are already set from operator redo
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 701e068d3fa..503e7bd4691 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -531,17 +531,12 @@ typedef struct TransInfo {
bool is_launch_event_tweak;
struct {
- /** Orientation type when when we're not constrained.
- * nearly always global except for rotate which defaults to screen-space orientation. */
- short unset;
- /** Orientation to use when a key is pressed. */
- short user;
- /* Used when user is global. */
- short user_alt;
short index;
- short *types[2];
- /* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */
+ short types[3];
+ /* this gets used when orientation.type[x] is V3D_ORIENT_CUSTOM */
struct TransformOrientation *custom;
+ /* this gets used when orientation.type[0] is V3D_ORIENT_CUSTOM_MATRIX */
+ float custom_matrix[3][3];
} orientation;
/** backup from view3d, to restore on end. */
short gizmo_flag;
@@ -566,15 +561,6 @@ typedef struct TransInfo {
/** Secondary axis, shear uses this. */
int orient_axis_ortho;
- /** Often this matrix has similar usage to #TransInfo.spacemtx however this
- * is used to define extra axes to operate on, not necessarily a space.
- *
- * For example, by default rotation operates on the view (`orient_matrix[2]`),
- * even when the current space isn't set to the view. */
- float orient_matrix[3][3];
- /** Don't overwrite when set by operator redo defines the orientation axis. */
- bool orient_matrix_is_set;
-
/** remove elements if operator is canceled. */
bool remove_on_cancel;
@@ -677,6 +663,10 @@ enum {
T_MODAL_CURSOR_SET = 1 << 26,
T_CLNOR_REBUILD = 1 << 27,
+
+ /* Special Aftertrans. */
+ T_AUTOMERGE = 1 << 28,
+ T_AUTOSPLIT = 1 << 29,
};
/** #TransInfo.modifiers */
@@ -922,7 +912,7 @@ void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot);
/*********************** Transform Orientations ******************************/
-void initTransformOrientation(struct bContext *C, TransInfo *t);
+void initTransformOrientation(struct bContext *C, TransInfo *t, short orientation);
/* Those two fill in mat and return non-zero on success */
bool createSpaceNormal(float mat[3][3], const float normal[3]);
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index cdff9fdf750..94cfed32841 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -713,7 +713,10 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char fte
break;
case V3D_ORIENT_VIEW:
BLI_snprintf(text, sizeof(text), ftext, TIP_("view"));
- setConstraint(t, t->spacemtx, mode, text);
+ float mtx[3][3];
+ copy_m3_m3(mtx, t->spacemtx);
+ negate_v3(mtx[2]);
+ setConstraint(t, mtx, mode, text);
break;
case V3D_ORIENT_CURSOR:
BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor"));
@@ -984,17 +987,22 @@ void getConstraintMatrix(TransInfo *t)
/*------------------------- MMB Select -------------------------------*/
-void initSelectConstraint(TransInfo *t, float mtx[3][3])
+void initSelectConstraint(TransInfo *t, bool force_global)
{
- copy_m3_m3(t->con.mtx, mtx);
- t->con.mode |= CON_APPLY;
- t->con.mode |= CON_SELECT;
+ short orientation;
+ if (force_global) {
+ orientation = V3D_ORIENT_GLOBAL;
+ }
+ else {
+ if (t->orientation.index == 0) {
+ t->orientation.index = 1;
+ initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]);
+ }
+ orientation = t->orientation.types[t->orientation.index];
+ }
+ setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, "");
setNearestAxis(t);
- t->con.drawExtra = NULL;
- t->con.applyVec = applyAxisConstraintVec;
- t->con.applySize = applyAxisConstraintSize;
- t->con.applyRot = applyAxisConstraintRot;
}
void selectConstraint(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h
index 8938ca93ad8..c98234c83da 100644
--- a/source/blender/editors/transform/transform_constraints.h
+++ b/source/blender/editors/transform/transform_constraints.h
@@ -36,7 +36,7 @@ void drawPropCircle(const struct bContext *C, TransInfo *t);
void startConstraint(TransInfo *t);
void stopConstraint(TransInfo *t);
void getConstraintMatrix(TransInfo *t);
-void initSelectConstraint(TransInfo *t, float mtx[3][3]);
+void initSelectConstraint(TransInfo *t, bool force_global);
void selectConstraint(TransInfo *t);
void postSelectConstraint(TransInfo *t);
void setNearestAxis(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 6744f7b6262..62fdaa4908e 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -447,12 +447,12 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
}
}
-/* sets transform flags in the bones
- * returns total number of bones with BONE_TRANSFORM */
-int count_set_pose_transflags(Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2])
+/* Sets transform flags in the bones.
+ * Returns total number of bones with `BONE_TRANSFORM`. */
+int transform_convert_pose_transflags_update(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2])
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
@@ -1846,8 +1846,8 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t)
static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
{
- /* so automerge supports mirror */
- if ((t->scene->toolsettings->automerge) && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
+ bool use_automerge = (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
+ if (use_automerge && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
@@ -1873,14 +1873,12 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
hflag = BM_ELEM_SELECT;
}
- if (t->scene->toolsettings->automerge & AUTO_MERGE) {
- if (t->scene->toolsettings->automerge & AUTO_MERGE_AND_SPLIT) {
- EDBM_automerge_and_split(
- tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
- }
- else {
- EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
- }
+ if (t->flag & T_AUTOSPLIT) {
+ EDBM_automerge_and_split(
+ tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
+ }
+ else {
+ EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
}
/* Special case, this is needed or faces won't re-select.
@@ -2288,7 +2286,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
if (!canceled && (t->mode != TFM_DUMMY)) {
- count_set_pose_transflags(ob, t->mode, t->around, NULL);
+ transform_convert_pose_transflags_update(ob, t->mode, t->around, NULL);
}
/* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index f975d320e62..fccaeb994e9 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -37,10 +37,10 @@ struct bKinematicConstraint;
struct bPoseChannel;
/* transform_convert.c */
-int count_set_pose_transflags(Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2]);
+int transform_convert_pose_transflags_update(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2]);
void transform_autoik_update(TransInfo *t, short mode);
void autokeyframe_object(struct bContext *C,
struct Scene *scene,
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 779257ef671..35bb7e3f0d8 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -609,9 +609,9 @@ void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *
/* TODO(germano): Realitve Mirror support */
}
data->flag |= CONSTRAINT_IK_AUTO;
- /* Add a temporary auto IK constraint here, as we will only temporarly active this targetless
- * bone during transform. (Targetless IK constraints are treated as if they are disabled
- * unless they are transformed) */
+ /* Add a temporary auto IK constraint here, as we will only temporarily active this
+ * target-less bone during transform. (Target-less IK constraints are treated as if they are
+ * disabled unless they are transformed) */
add_temporary_ik_constraint(pchan, data);
Main *bmain = CTX_data_main(t->context);
update_deg_with_temporary_ik(bmain, ob);
@@ -669,7 +669,9 @@ void createTransPose(TransInfo *t)
const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
/* set flags and count total */
- tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
+ tc->data_len = transform_convert_pose_transflags_update(
+ ob, t->mode, t->around, has_translate_rotate);
+
if (tc->data_len == 0) {
continue;
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 05318a5c1d3..a21df9f66f5 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1431,11 +1431,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
unit_m3(t->mat);
- unit_m3(t->orient_matrix);
- negate_m3(t->orient_matrix);
- /* Leave 't->orient_matrix_is_set' to false,
- * so we overwrite it when we have a useful value. */
-
/* Default to rotate on the Z axis. */
t->orient_axis = 2;
t->orient_axis_ortho = 1;
@@ -1513,22 +1508,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CURSOR;
}
- TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
- t->orientation.unset = V3D_ORIENT_GLOBAL;
- t->orientation.user = orient_slot->type;
- t->orientation.custom = BKE_scene_transform_orientation_find(t->scene,
- orient_slot->index_custom);
-
- t->orientation.index = 0;
- ARRAY_SET_ITEMS(t->orientation.types, &t->orientation.user, NULL);
-
- /* Make second orientation local if both are global. */
- if (t->orientation.user == V3D_ORIENT_GLOBAL) {
- t->orientation.user_alt = V3D_ORIENT_LOCAL;
- t->orientation.types[0] = &t->orientation.user_alt;
- SWAP(short *, t->orientation.types[0], t->orientation.types[1]);
- }
-
/* exceptional case */
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
@@ -1617,48 +1596,100 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CENTER_BOUNDS;
}
- if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
- t->orient_axis = RNA_property_enum_get(op->ptr, prop);
- }
- if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
- t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
- }
+ if (op && (prop = RNA_struct_find_property(op->ptr, "constraint_axis")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ bool constraint_axis[3];
- if (op &&
- ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
- RNA_property_is_set(op->ptr, prop)) &&
- ((t->flag & T_MODAL) ||
- /* When using redo, don't use the custom constraint matrix
- * if the user selects a different orientation. */
- (RNA_enum_get(op->ptr, "orient_type") == RNA_enum_get(op->ptr, "orient_matrix_type")))) {
- RNA_property_float_get_array(op->ptr, prop, &t->orient_matrix[0][0]);
- copy_m3_m3(t->spacemtx, t->orient_matrix);
- /* Some transform modes use this to operate on an axis. */
- t->orient_matrix_is_set = true;
- t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX;
- t->orientation.custom = 0;
- if (t->flag & T_MODAL) {
- RNA_enum_set(op->ptr, "orient_matrix_type", RNA_enum_get(op->ptr, "orient_type"));
+ RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
+
+ if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
+ t->con.mode |= CON_APPLY;
+
+ if (constraint_axis[0]) {
+ t->con.mode |= CON_AXIS0;
+ }
+ if (constraint_axis[1]) {
+ t->con.mode |= CON_AXIS1;
+ }
+ if (constraint_axis[2]) {
+ t->con.mode |= CON_AXIS2;
+ }
}
}
- else if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
- RNA_property_is_set(op->ptr, prop))) {
- short orientation = RNA_property_enum_get(op->ptr, prop);
+
+ {
TransformOrientation *custom_orientation = NULL;
+ short orient_type_default = V3D_ORIENT_GLOBAL;
+ short orient_type_set = -1;
+ short orient_type_matrix_set = -1;
+ short orient_type_constraint = -1;
+
+ if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
+ t->orient_axis = RNA_property_enum_get(op->ptr, prop);
+ orient_type_default = V3D_ORIENT_VIEW;
+ }
+ if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
+ t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
+ }
+
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
+ RNA_property_is_set(op->ptr, prop))) {
+ orient_type_set = RNA_property_enum_get(op->ptr, prop);
+ }
+
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
+ RNA_property_is_set(op->ptr, prop))) {
+ RNA_property_float_get_array(op->ptr, prop, &t->orientation.custom_matrix[0][0]);
- if (orientation >= V3D_ORIENT_CUSTOM) {
- if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
- orientation = V3D_ORIENT_GLOBAL;
+ if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop);
}
else {
+ orient_type_matrix_set = orient_type_set;
+ }
+
+ if (orient_type_matrix_set == orient_type_set) {
+ /* When using redo, don't use the custom constraint matrix
+ * if the user selects a different orientation. */
+ orient_type_default = V3D_ORIENT_CUSTOM_MATRIX;
+ orient_type_constraint = orient_type_set;
+ }
+ }
+
+ if (orient_type_constraint == -1) {
+ if (orient_type_set != -1) {
+ orient_type_default = orient_type_set;
+
+ if (orient_type_default >= V3D_ORIENT_CUSTOM) {
+ if (orient_type_default >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
+ orient_type_default = V3D_ORIENT_GLOBAL;
+ }
+ else {
+ custom_orientation = BKE_scene_transform_orientation_find(
+ t->scene, orient_type_default - V3D_ORIENT_CUSTOM);
+ orient_type_default = V3D_ORIENT_CUSTOM;
+ }
+ }
+ orient_type_constraint = orient_type_default;
+ }
+ else {
+ TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
+ orient_type_constraint = orient_slot->type;
custom_orientation = BKE_scene_transform_orientation_find(t->scene,
- orientation - V3D_ORIENT_CUSTOM);
- orientation = V3D_ORIENT_CUSTOM;
+ orient_slot->index_custom);
}
}
- t->orientation.user = orientation;
+ t->orientation.types[0] = orient_type_default;
+ t->orientation.types[1] = orient_type_constraint;
+ t->orientation.types[2] = orient_type_constraint != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL :
+ V3D_ORIENT_LOCAL;
t->orientation.custom = custom_orientation;
+
+ if (t->con.mode & CON_APPLY) {
+ t->orientation.index = 1;
+ }
}
if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
@@ -1763,6 +1794,24 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->options |= CTX_NO_PET;
}
+ if (t->obedit_type == OB_MESH) {
+ if (op && (prop = RNA_struct_find_property(op->ptr, "use_automerge_and_split")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
+ t->flag |= T_AUTOMERGE | T_AUTOSPLIT;
+ }
+ }
+ else {
+ char automerge = t->scene->toolsettings->automerge;
+ if (automerge & AUTO_MERGE) {
+ t->flag |= T_AUTOMERGE;
+ if (automerge & AUTO_MERGE_AND_SPLIT) {
+ t->flag |= T_AUTOSPLIT;
+ }
+ }
+ }
+ }
+
// Mirror is not supported with PET, turn it off.
#if 0
if (t->flag & T_PROP_EDIT) {
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index aa298b04d1a..362cbc1b800 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -1033,7 +1033,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
/* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */
const int mode = TFM_ROTATION;
- const int totsel_iter = count_set_pose_transflags(
+ const int totsel_iter = transform_convert_pose_transflags_update(
ob_iter, mode, V3D_AROUND_CENTER_BOUNDS, NULL);
if (totsel_iter) {
@@ -1402,7 +1402,7 @@ void drawDial3d(const TransInfo *t)
}
else {
axis_idx = MAN_AXIS_ROT_C;
- negate_v3_v3(mat_basis[2], t->orient_matrix[t->orient_axis]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]);
scale *= 1.2f;
line_with -= 1.0f;
}
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index a2b3a891031..4c14c3aebd7 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -529,7 +529,7 @@ void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final)
void postInputRotation(TransInfo *t, float values[3])
{
float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, NULL, axis_final, values);
}
diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
index 18149a09f20..fde0d5b187e 100644
--- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
+++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
@@ -81,7 +81,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, NULL, axis_final, NULL);
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index 6c2b3dc77d2..f52bfda0d14 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -146,7 +146,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
snapGridIncrement(t, &final);
float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, NULL, axis_final, NULL);
diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c
index ba79f5f3c7b..da34bf50ba3 100644
--- a/source/blender/editors/transform/transform_mode_shear.c
+++ b/source/blender/editors/transform/transform_mode_shear.c
@@ -53,17 +53,17 @@ static void initShear_mouseInputMode(TransInfo *t)
{
float dir[3];
bool dir_flip = false;
- copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
+ copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]);
/* Needed for axis aligned view gizmo. */
- if (t->orientation.user == V3D_ORIENT_VIEW) {
+ if (t->orientation.types[t->orientation.index] == V3D_ORIENT_VIEW) {
if (t->orient_axis_ortho == 0) {
- if (t->center2d[1] > t->mouse.imval[1]) {
+ if (t->center2d[1] < t->mouse.imval[1]) {
dir_flip = !dir_flip;
}
}
else if (t->orient_axis_ortho == 1) {
- if (t->center2d[0] > t->mouse.imval[0]) {
+ if (t->center2d[0] < t->mouse.imval[0]) {
dir_flip = !dir_flip;
}
}
@@ -154,8 +154,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
unit_m3(smat);
smat[1][0] = value;
- copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]);
- copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(axismat_inv[0], t->spacemtx[t->orient_axis_ortho]);
+ copy_v3_v3(axismat_inv[2], t->spacemtx[t->orient_axis]);
cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]);
invert_m3_m3(axismat, axismat_inv);
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 36f42992573..d643244e6ca 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -716,6 +716,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
+
+ if (flags & P_POST_TRANSFORM) {
+ prop = RNA_def_boolean(ot->srna,
+ "use_automerge_and_split",
+ 0,
+ "Auto Merge & Split",
+ "Forces the use of Auto Merge & Split");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ }
}
static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
@@ -741,7 +750,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP |
- P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT);
+ P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_POST_TRANSFORM);
}
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 76823adfd20..3b1f3559daa 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -407,14 +407,19 @@ bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3]
return true;
}
-static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
+/* Updates all `BONE_TRANSFORM` flags.
+ * Returns total number of bones with `BONE_TRANSFORM`.
+ * Note: `transform_convert_pose_transflags_update` has a similar logic. */
+static int armature_bone_transflags_update_recursive(bArmature *arm,
+ ListBase *lb,
+ const bool do_it)
{
Bone *bone;
bool do_next;
int total = 0;
for (bone = lb->first; bone; bone = bone->next) {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ bone->flag &= ~BONE_TRANSFORM;
do_next = do_it;
if (do_it) {
if (bone->layer & arm->layer) {
@@ -427,18 +432,18 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
}
}
}
- total += count_bone_select(arm, &bone->childbase, do_next);
+ total += armature_bone_transflags_update_recursive(arm, &bone->childbase, do_next);
}
return total;
}
-void initTransformOrientation(bContext *C, TransInfo *t)
+void initTransformOrientation(bContext *C, TransInfo *t, short orientation)
{
Object *ob = CTX_data_active_object(C);
Object *obedit = CTX_data_active_object(C);
- switch (t->orientation.user) {
+ switch (orientation) {
case V3D_ORIENT_GLOBAL:
unit_m3(t->spacemtx);
BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename));
@@ -471,28 +476,28 @@ void initTransformOrientation(bContext *C, TransInfo *t)
break;
- case V3D_ORIENT_VIEW:
+ case V3D_ORIENT_VIEW: {
+ float mat[3][3];
if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
- RegionView3D *rv3d = t->region->regiondata;
- float mat[3][3];
-
BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename));
- copy_m3_m4(mat, rv3d->viewinv);
+ copy_m3_m4(mat, t->viewinv);
normalize_m3(mat);
- copy_m3_m3(t->spacemtx, mat);
}
else {
- unit_m3(t->spacemtx);
+ unit_m3(mat);
}
+ negate_v3(mat[2]);
+ copy_m3_m3(t->spacemtx, mat);
break;
+ }
case V3D_ORIENT_CURSOR: {
BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename));
BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx);
break;
}
case V3D_ORIENT_CUSTOM_MATRIX:
- /* Already set. */
BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename));
+ copy_m3_m3(t->spacemtx, t->orientation.custom_matrix);
break;
case V3D_ORIENT_CUSTOM:
BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename));
@@ -505,20 +510,6 @@ void initTransformOrientation(bContext *C, TransInfo *t)
}
break;
}
-
- if (t->orient_matrix_is_set == false) {
- t->orient_matrix_is_set = true;
- if (t->flag & T_MODAL) {
- /* Rotate for example defaults to operating on the view plane. */
- t->orientation.unset = V3D_ORIENT_VIEW;
- copy_m3_m4(t->orient_matrix, t->viewinv);
- normalize_m3(t->orient_matrix);
- negate_m3(t->orient_matrix);
- }
- else {
- copy_m3_m3(t->orient_matrix, t->spacemtx);
- }
- }
}
/**
@@ -1072,10 +1063,9 @@ int getTransformOrientation_ex(const bContext *C,
ok = true;
}
else {
- int totsel;
-
- totsel = count_bone_select(arm, &arm->bonebase, true);
- if (totsel) {
+ int transformed_len;
+ transformed_len = armature_bone_transflags_update_recursive(arm, &arm->bonebase, true);
+ if (transformed_len) {
/* use channels to get stats */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index d2ba9ab9591..b40b82c50fb 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -40,6 +40,7 @@ set(SRC
uvedit_draw.c
uvedit_ops.c
uvedit_parametrizer.c
+ uvedit_select.c
uvedit_smart_stitch.c
uvedit_unwrap_ops.c
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 6ea1bbbcc10..959ca1eeef1 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -306,6 +306,7 @@ static void draw_uvs(SpaceImage *sima,
Object *ob_eval = batch->ob_eval;
const ToolSettings *ts = scene->toolsettings;
float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float overlay_alpha = sima->uv_opacity;
if (sima->flag & SI_DRAWSHADOW) {
bool is_cage_like_final_meshes = false;
@@ -346,7 +347,11 @@ static void draw_uvs(SpaceImage *sima,
UI_GetThemeColor4fv(TH_FACE, col1);
UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3);
- col3[3] *= 0.2; /* Simulate dithering */
+
+ col1[3] *= overlay_alpha;
+ col2[3] *= overlay_alpha;
+ col3[3] *= overlay_alpha;
+
GPU_batch_uniform_4fv(batch->faces, "faceColor", col1);
GPU_batch_uniform_4fv(batch->faces, "selectColor", col2);
GPU_batch_uniform_4fv(batch->faces, "activeColor", col3);
@@ -372,9 +377,16 @@ static void draw_uvs(SpaceImage *sima,
GPU_line_smooth(true);
GPU_blend(true);
}
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(true);
+ }
+
switch (sima->dt_uv) {
case SI_UVDT_DASH: {
- float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}};
+ float dash_colors[2][4] = {
+ {0.56f, 0.56f, 0.56f, overlay_alpha},
+ {0.07f, 0.07f, 0.07f, overlay_alpha},
+ };
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -398,7 +410,8 @@ static void draw_uvs(SpaceImage *sima,
* instead of modifying the provoking vert. */
glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
- UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
+ UI_GetThemeColor3fv(TH_EDGE_SELECT, col2);
+ col2[3] = overlay_alpha;
GPU_batch_program_set_builtin(
batch->edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
@@ -406,18 +419,19 @@ static void draw_uvs(SpaceImage *sima,
if (sima->dt_uv == SI_UVDT_OUTLINE) {
/* Black Outline. */
GPU_line_width(3.0f);
- GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, 1.0f);
- GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, 1.0f);
+ GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, overlay_alpha);
+ GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, overlay_alpha);
GPU_batch_draw(batch->edges);
- UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
+ UI_GetThemeColor3fv(TH_WIRE_EDIT, col1);
}
else if (sima->dt_uv == SI_UVDT_WHITE) {
- copy_v4_fl4(col1, 1.0f, 1.0f, 1.0f, 1.0f);
+ copy_v3_fl3(col1, 1.0f, 1.0f, 1.0f);
}
else {
- copy_v4_fl4(col1, 0.0f, 0.0f, 0.0f, 1.0f);
+ copy_v3_fl3(col1, 0.0f, 0.0f, 0.0f);
}
+ col1[3] = overlay_alpha;
/* Inner Line. Use depth test to insure selection is drawn on top. */
GPU_depth_test(true);
@@ -435,6 +449,9 @@ static void draw_uvs(SpaceImage *sima,
GPU_line_smooth(false);
GPU_blend(false);
}
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(false);
+ }
}
if (batch->verts || batch->facedots) {
UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2);
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 7bc6b048585..ffab5bd094f 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -99,6 +99,7 @@ bool uv_find_nearest_face_multi(struct Scene *scene,
void uvedit_live_unwrap_update(struct SpaceImage *sima,
struct Scene *scene,
struct Object *obedit);
+void uvedit_pixel_to_float(struct SpaceImage *sima, float pixeldist, float r_dist[2]);
/* operators */
@@ -113,4 +114,31 @@ void UV_OT_sphere_project(struct wmOperatorType *ot);
void UV_OT_unwrap(struct wmOperatorType *ot);
void UV_OT_stitch(struct wmOperatorType *ot);
+/* uvedit_select.c */
+
+bool uvedit_select_is_any_selected(struct Scene *scene, struct Image *ima, struct Object *obedit);
+bool uvedit_select_is_any_selected_multi(struct Scene *scene,
+ struct Image *ima,
+ struct Object **objects,
+ const uint objects_len);
+const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene,
+ struct Object *obedit,
+ struct Image *ima,
+ struct BMVert *eve,
+ const int cd_loop_uv_offset);
+
+void UV_OT_select_all(struct wmOperatorType *ot);
+void UV_OT_select(struct wmOperatorType *ot);
+void UV_OT_select_loop(struct wmOperatorType *ot);
+void UV_OT_select_linked(struct wmOperatorType *ot);
+void UV_OT_select_linked_pick(struct wmOperatorType *ot);
+void UV_OT_select_split(struct wmOperatorType *ot);
+void UV_OT_select_pinned(struct wmOperatorType *ot);
+void UV_OT_select_box(struct wmOperatorType *ot);
+void UV_OT_select_lasso(struct wmOperatorType *ot);
+void UV_OT_select_circle(struct wmOperatorType *ot);
+void UV_OT_select_more(struct wmOperatorType *ot);
+void UV_OT_select_less(struct wmOperatorType *ot);
+void UV_OT_select_overlap(struct wmOperatorType *ot);
+
#endif /* __UVEDIT_INTERN_H__ */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index e169222380e..a99e05cb52b 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -36,15 +36,9 @@
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
-#include "BLI_alloca.h"
#include "BLI_array.h"
-#include "BLI_blenlib.h"
-#include "BLI_hash.h"
-#include "BLI_kdopbvh.h"
#include "BLI_kdtree.h"
-#include "BLI_lasso_2d.h"
#include "BLI_math.h"
-#include "BLI_polyfill_2d.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -52,31 +46,22 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
-#include "BKE_image.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_material.h"
-#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_node.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_node.h"
-#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
-#include "ED_transform.h"
#include "ED_uvedit.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_message.h"
@@ -88,26 +73,6 @@
#include "uvedit_intern.h"
-static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit);
-static bool uv_select_is_any_selected_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len);
-static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action);
-static void uv_select_all_perform_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
-static void uv_select_flush_from_tag_face(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select);
-static void uv_select_flush_from_tag_loop(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select);
-static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
- const ToolSettings *ts,
- Object *obedit);
-
/* -------------------------------------------------------------------- */
/** \name State Testing
* \{ */
@@ -225,7 +190,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
/** \name Space Conversion
* \{ */
-static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
+void uvedit_pixel_to_float(SpaceImage *sima, float pixeldist, float r_dist[2])
{
int width, height;
@@ -237,351 +202,8 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist
height = IMG_SIZE_FALLBACK;
}
- dist[0] = pixeldist / width;
- dist[1] = pixeldist / height;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Visibility and Selection Utilities
- * \{ */
-
-static void uvedit_vertex_select_tagged(BMEditMesh *em,
- Scene *scene,
- bool select,
- int cd_loop_uv_offset)
-{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
-}
-
-bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
- }
- else {
- return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
- }
-}
-bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa)
-{
- return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa);
-}
-
-bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa)
-{
- if (ts->uv_flag & UV_SHOW_SAME_IMAGE) {
- Image *face_image;
- ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL);
- return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false;
- }
- else {
- return uvedit_face_visible_nolocal_ex(ts, efa);
- }
-}
-bool uvedit_face_visible_test(const Scene *scene, Object *obedit, Image *ima, BMFace *efa)
-{
- return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa);
-}
-
-bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (!(luv->flag & MLOOPUV_VERTSEL)) {
- return false;
- }
- }
-
- return true;
- }
-}
-bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
-{
- return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
-}
-
-bool uvedit_face_select_set(const struct Scene *scene,
- struct BMEditMesh *em,
- struct BMFace *efa,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- if (select) {
- return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
- }
- else {
- return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
- }
-}
-
-bool uvedit_face_select_enable(const Scene *scene,
- BMEditMesh *em,
- BMFace *efa,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BM_face_select_set(em->bm, efa, true);
- if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)efa);
- }
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
- }
-
- return true;
- }
-
- return false;
-}
-
-bool uvedit_face_select_disable(const Scene *scene,
- BMEditMesh *em,
- BMFace *efa,
- const int cd_loop_uv_offset)
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BM_face_select_set(em->bm, efa, false);
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
-
- return true;
- }
-
- return false;
-}
-
-bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
- }
- else if (ts->selectmode == SCE_SELECT_EDGE) {
- return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
- }
- else {
- return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
- BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
- }
-}
-bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
-{
- return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
-}
-
-void uvedit_edge_select_set(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset)
-
-{
- if (select) {
- uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
- }
- else {
- uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset);
- }
-}
-
-void uvedit_edge_select_enable(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset)
-
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, true);
- }
- else if (ts->selectmode & SCE_SELECT_EDGE) {
- BM_edge_select_set(em->bm, l->e, true);
- }
- else {
- BM_vert_select_set(em->bm, l->e->v1, true);
- BM_vert_select_set(em->bm, l->e->v2, true);
- }
-
- if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)l->e);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- luv1->flag |= MLOOPUV_VERTSEL;
- luv2->flag |= MLOOPUV_VERTSEL;
- }
-}
-
-void uvedit_edge_select_disable(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const int cd_loop_uv_offset)
-
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, false);
- }
- else if (ts->selectmode & SCE_SELECT_EDGE) {
- BM_edge_select_set(em->bm, l->e, false);
- }
- else {
- BM_vert_select_set(em->bm, l->e->v1, false);
- BM_vert_select_set(em->bm, l->e->v2, false);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- luv1->flag &= ~MLOOPUV_VERTSEL;
- luv2->flag &= ~MLOOPUV_VERTSEL;
- }
-}
-
-bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
- }
- else {
- return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
- }
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- return (luv->flag & MLOOPUV_VERTSEL) != 0;
- }
-}
-bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
-{
- return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
-}
-
-void uvedit_uv_select_set(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- if (select) {
- uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
- }
- else {
- uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset);
- }
-}
-
-void uvedit_uv_select_enable(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, true);
- }
- else {
- BM_vert_select_set(em->bm, l->v, true);
- }
-
- if (do_history) {
- BM_select_history_remove(em->bm, (BMElem *)l->v);
- }
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
- }
-}
-
-void uvedit_uv_select_disable(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const int cd_loop_uv_offset)
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, false);
- }
- else {
- BM_vert_select_set(em->bm, l->v, false);
- }
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
+ r_dist[0] = pixeldist / width;
+ r_dist[1] = pixeldist / height;
}
/** \} */
@@ -770,7 +392,8 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima,
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- *r_has_select = uv_select_is_any_selected_multi(scene, sima->image, objects, objects_len);
+ *r_has_select = uvedit_select_is_any_selected_multi(
+ scene, sima->image, objects, objects_len);
MEM_freeN(objects);
}
break;
@@ -799,877 +422,6 @@ bool ED_uvedit_center_from_pivot(
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Find Nearest Elements
- * \{ */
-
-bool uv_find_nearest_edge(
- Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv, *luv_next;
- int i;
- bool found = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
-
- if (dist_test_sq < hit->dist_sq) {
- hit->efa = efa;
-
- hit->l = l;
- hit->luv = luv;
- hit->luv_next = luv_next;
- hit->lindex = i;
-
- hit->dist_sq = dist_test_sq;
- found = true;
- }
- }
- }
- return found;
-}
-
-bool uv_find_nearest_edge_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float co[2],
- UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
-}
-
-bool uv_find_nearest_face(
- Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- bool found = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* this will fill in hit.vert1 and hit.vert2 */
- float dist_sq_init = hit_final->dist_sq;
- UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
- hit.dist_sq = dist_sq_init;
- hit.l = NULL;
- hit.luv = hit.luv_next = NULL;
-
- BMIter iter;
- BMFace *efa;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
-
- const float dist_test_sq = len_squared_v2v2(co, cent);
-
- if (dist_test_sq < hit.dist_sq) {
- hit.efa = efa;
- hit.dist_sq = dist_test_sq;
- found = true;
- }
- }
- }
- if (found) {
- *hit_final = hit;
- }
- return found;
-}
-
-bool uv_find_nearest_face_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float co[2],
- UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
-}
-
-static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
-{
- const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
- const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
- const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
-
- return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
- (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
-}
-
-bool uv_find_nearest_vert(Scene *scene,
- Image *ima,
- Object *obedit,
- float const co[2],
- const float penalty_dist,
- UvNearestHit *hit_final)
-{
- bool found = false;
-
- /* this will fill in hit.vert1 and hit.vert2 */
- float dist_sq_init = hit_final->dist_sq;
- UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
- hit.dist_sq = dist_sq_init;
-
- hit.l = NULL;
- hit.luv = hit.luv_next = NULL;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMIter iter;
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BMIter liter;
- BMLoop *l;
- int i;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- float dist_test_sq;
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
- dist_test_sq = square_f(dist_test_sq);
- }
- else {
- dist_test_sq = len_squared_v2v2(co, luv->uv);
- }
-
- if (dist_test_sq <= hit.dist_sq) {
- if (dist_test_sq == hit.dist_sq) {
- if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
- continue;
- }
- }
-
- hit.dist_sq = dist_test_sq;
-
- hit.l = l;
- hit.luv = luv;
- hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- hit.efa = efa;
- hit.lindex = i;
- found = true;
- }
- }
- }
- }
-
- if (found) {
- *hit_final = hit;
- }
-
- return found;
-}
-
-bool uv_find_nearest_vert_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- float const co[2],
- const float penalty_dist,
- UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
-}
-
-bool ED_uvedit_nearest_uv(const Scene *scene,
- Object *obedit,
- Image *ima,
- const float co[2],
- float *dist_sq,
- float r_uv[2])
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMIter iter;
- BMFace *efa;
- const float *uv_best = NULL;
- float dist_best = *dist_sq;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
- const float dist_test = len_squared_v2v2(co, uv);
- if (dist_best > dist_test) {
- dist_best = dist_test;
- uv_best = uv;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- if (uv_best != NULL) {
- copy_v2_v2(r_uv, uv_best);
- *dist_sq = dist_best;
- return true;
- }
- else {
- return false;
- }
-}
-
-bool ED_uvedit_nearest_uv_multi(const Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float co[2],
- float *dist_sq,
- float r_uv[2])
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) {
- found = true;
- }
- }
- return found;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Loop Select
- * \{ */
-
-static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
-{
- UvMapVert *iterv;
- int count = 0;
-
- for (iterv = first; iterv; iterv = iterv->next) {
- if (iterv->separate && iterv != first) {
- break;
- }
-
- count++;
- }
-
- if (count < 5) {
- first->flag = 1;
- }
-}
-
-static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l)
-{
- UvMapVert *iterv, *first;
- first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- for (iterv = first; iterv; iterv = iterv->next) {
- if (iterv->separate) {
- first = iterv;
- }
- if (iterv->poly_index == BM_elem_index_get(efa)) {
- return first;
- }
- }
-
- return NULL;
-}
-
-static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em,
- UvMapVert *first1,
- UvMapVert *first2,
- int *totface)
-{
- UvMapVert *iterv1, *iterv2;
- BMFace *efa;
- int tot = 0;
-
- /* count number of faces this edge has */
- for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
- if (iterv1->separate && iterv1 != first1) {
- break;
- }
-
- for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
- if (iterv2->separate && iterv2 != first2) {
- break;
- }
-
- if (iterv1->poly_index == iterv2->poly_index) {
- /* if face already tagged, don't do this edge */
- efa = BM_face_at_index(em->bm, iterv1->poly_index);
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- return false;
- }
-
- tot++;
- break;
- }
- }
- }
-
- if (*totface == 0) { /* start edge */
- *totface = tot;
- }
- else if (tot != *totface) { /* check for same number of faces as start edge */
- return false;
- }
-
- /* tag the faces */
- for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
- if (iterv1->separate && iterv1 != first1) {
- break;
- }
-
- for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
- if (iterv2->separate && iterv2 != first2) {
- break;
- }
-
- if (iterv1->poly_index == iterv2->poly_index) {
- efa = BM_face_at_index(em->bm, iterv1->poly_index);
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- break;
- }
- }
- }
-
- return true;
-}
-
-static int uv_select_edgeloop(Scene *scene,
- Image *ima,
- Object *obedit,
- UvNearestHit *hit,
- const float limit[2],
- const bool extend)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMIter iter, liter;
- BMLoop *l;
- UvVertMap *vmap;
- UvMapVert *iterv_curr;
- UvMapVert *iterv_next;
- int starttotf;
- bool looking, select;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* setup */
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
-
- if (!extend) {
- uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
- }
-
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
-
- /* set flags for first face and verts */
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
- iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
- uv_select_edgeloop_vertex_loop_flag(iterv_curr);
- uv_select_edgeloop_vertex_loop_flag(iterv_next);
-
- starttotf = 0;
- uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf);
-
- /* sorry, first edge isn't even ok */
- looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0);
-
- /* iterate */
- while (looking) {
- looking = false;
-
- /* find correct valence edges which are not tagged yet, but connect to tagged one */
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG) &&
- uvedit_face_visible_test(scene, obedit, ima, efa)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- /* check face not hidden and not tagged */
- if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) {
- continue;
- }
- if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) {
- continue;
- }
-
- /* check if vertex is tagged and has right valence */
- if (iterv_curr->flag || iterv_next->flag) {
- if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) {
- looking = true;
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
-
- uv_select_edgeloop_vertex_loop_flag(iterv_curr);
- uv_select_edgeloop_vertex_loop_flag(iterv_next);
- break;
- }
- }
- }
- }
- }
- }
-
- /* do the actual select/deselect */
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
- iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
- iterv_curr->flag = 1;
- iterv_next->flag = 1;
-
- if (extend) {
- select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
- }
- else {
- select = true;
- }
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l);
-
- if (iterv_curr->flag) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
-
- /* cleanup */
- BM_uv_vert_map_free(vmap);
-
- return (select) ? 1 : -1;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Linked
- * \{ */
-
-static void uv_select_linked_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float limit[2],
- UvNearestHit *hit_final,
- bool extend,
- bool deselect,
- bool toggle,
- bool select_faces)
-{
- /* loop over objects, or just use hit_final->ob */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- if (hit_final && ob_index != 0) {
- break;
- }
- Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
-
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- UvVertMap *vmap;
- UvMapVert *vlist, *iterv, *startv;
- int i, stacksize = 0, *stack;
- uint a;
- char *flag;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
-
- /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
- * this made *every* projection split the island into front/back islands.
- * Keep 'use_winding' to false, see: T50970.
- *
- * Better solve this by having a delimit option for select-linked operator,
- * keeping island-select working as is. */
- vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
-
- if (vmap == NULL) {
- continue;
- }
-
- stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
- flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
-
- if (hit_final == NULL) {
- /* Use existing selection */
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- if (select_faces) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
-
- break;
- }
- }
- }
- }
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (efa == hit_final->efa) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
- break;
- }
- }
- }
-
- while (stacksize > 0) {
-
- stacksize--;
- a = stack[stacksize];
-
- efa = BM_face_at_index(em->bm, a);
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
-
- /* make_uv_vert_map_EM sets verts tmp.l to the indices */
- vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- startv = vlist;
-
- for (iterv = vlist; iterv; iterv = iterv->next) {
- if (iterv->separate) {
- startv = iterv;
- }
- if (iterv->poly_index == a) {
- break;
- }
- }
-
- for (iterv = startv; iterv; iterv = iterv->next) {
- if ((startv != iterv) && (iterv->separate)) {
- break;
- }
- else if (!flag[iterv->poly_index]) {
- flag[iterv->poly_index] = 1;
- stack[stacksize] = iterv->poly_index;
- stacksize++;
- }
- }
- }
- }
-
- /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
- if ((toggle == true) && (extend == false) && (deselect == false)) {
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- bool found_selected = false;
- if (!flag[a]) {
- continue;
- }
-
- if (select_faces) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- found_selected = true;
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- found_selected = true;
- }
- }
-
- if (found_selected) {
- deselect = true;
- break;
- }
- }
- }
- }
-
-#define SET_SELECTION(value) \
- if (select_faces) { \
- BM_face_select_set(em->bm, efa, value); \
- } \
- else { \
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
- luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
- } \
- } \
- (void)0
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (!flag[a]) {
- if (!extend && !deselect && !toggle) {
- SET_SELECTION(false);
- }
- continue;
- }
-
- if (!deselect) {
- SET_SELECTION(true);
- }
- else {
- SET_SELECTION(false);
- }
- }
-
-#undef SET_SELECTION
-
- MEM_freeN(stack);
- MEM_freeN(flag);
- BM_uv_vert_map_free(vmap);
- }
-}
-
-/* WATCH IT: this returns first selected UV,
- * not ideal in many cases since there could be multiple */
-static float *uv_sel_co_from_eve(
- Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve)
-{
- BMIter liter;
- BMLoop *l;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
- continue;
- }
-
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- return luv->uv;
- }
- }
-
- return NULL;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select More/Less Operator
- * \{ */
-
-static int uv_select_more_less(bContext *C, const bool select)
-{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- SpaceImage *sima = CTX_wm_space_image(C);
-
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- const ToolSettings *ts = scene->toolsettings;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (select) {
- EDBM_select_more(em, true);
- }
- else {
- EDBM_select_less(em, true);
- }
-
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- continue;
- }
-
- if (is_uv_face_selectmode) {
-
- /* clear tags */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
-
- /* mark loops to be selected */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
-
-#define IS_SEL 1
-#define IS_UNSEL 2
-
- int sel_state = 0;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_VERTSEL) {
- sel_state |= IS_SEL;
- }
- else {
- sel_state |= IS_UNSEL;
- }
-
- /* if we have a mixed selection, tag to grow it */
- if (sel_state == (IS_SEL | IS_UNSEL)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- break;
- }
- }
-
-#undef IS_SEL
-#undef IS_UNSEL
- }
- }
- }
- else {
-
- /* clear tags */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- BM_elem_flag_disable(l, BM_ELEM_TAG);
- }
- }
-
- /* mark loops to be selected */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
-
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
- BM_elem_flag_enable(l->next, BM_ELEM_TAG);
- BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
- }
- }
-
- if (changed) {
- if (is_uv_face_selectmode) {
- /* Select tagged faces. */
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- else {
- /* Select tagged loops. */
- uv_select_flush_from_tag_loop(sima, scene, obedit, select);
- }
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
-{
- return uv_select_more_less(C, true);
-}
-
-static void UV_OT_select_more(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select More";
- ot->description = "Select more UV vertices connected to initial selection";
- ot->idname = "UV_OT_select_more";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_more_exec;
- ot->poll = ED_operator_uvedit_space_image;
-}
-
-static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op))
-{
- return uv_select_more_less(C, false);
-}
-
-static void UV_OT_select_less(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Less";
- ot->description = "Deselect UV vertices at the boundary of each selection region";
- ot->idname = "UV_OT_select_less";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_less_exec;
- ot->poll = ED_operator_uvedit_space_image;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Weld Align Operator
* \{ */
@@ -1866,9 +618,10 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
if (BLI_array_len(eve_line) > 2) {
/* we know the returns from these must be valid */
- const float *uv_start = uv_sel_co_from_eve(scene, obedit, ima, em, eve_line[0]);
- const float *uv_end = uv_sel_co_from_eve(
- scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]);
+ const float *uv_start = uvedit_first_selected_uv_from_vertex(
+ scene, obedit, ima, eve_line[0], cd_loop_uv_offset);
+ const float *uv_end = uvedit_first_selected_uv_from_vertex(
+ scene, obedit, ima, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset);
/* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */
float a = 0.0f;
eUVWeldAlign tool_local = tool;
@@ -2316,1665 +1069,6 @@ static void UV_OT_weld(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name (De)Select All Operator
- * \{ */
-
-static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
-{
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
- }
- else {
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_VERTSEL) {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-static bool uv_select_is_any_selected_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_select_is_any_selected(scene, ima, obedit)) {
- found = true;
- break;
- }
- }
- return found;
-}
-
-static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
-{
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (action == SEL_TOGGLE) {
- action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
- }
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- switch (action) {
- case SEL_TOGGLE:
- EDBM_select_toggle_all(em);
- break;
- case SEL_SELECT:
- EDBM_flag_enable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_DESELECT:
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_INVERT:
- EDBM_select_swap(em);
- EDBM_selectmode_flush(em);
- break;
- }
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- switch (action) {
- case SEL_SELECT:
- luv->flag |= MLOOPUV_VERTSEL;
- break;
- case SEL_DESELECT:
- luv->flag &= ~MLOOPUV_VERTSEL;
- break;
- case SEL_INVERT:
- luv->flag ^= MLOOPUV_VERTSEL;
- break;
- }
- }
- }
- }
-}
-
-static void uv_select_all_perform_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
-{
- if (action == SEL_TOGGLE) {
- action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT :
- SEL_SELECT;
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_all_perform(scene, ima, obedit, action);
- }
-}
-
-static int uv_select_all_exec(bContext *C, wmOperator *op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
- int action = RNA_enum_get(op->ptr, "action");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
-
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static void UV_OT_select_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "(De)select All";
- ot->description = "Change selection of all UV vertices";
- ot->idname = "UV_OT_select_all";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_all_exec;
- ot->poll = ED_operator_uvedit;
-
- WM_operator_properties_select_all(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Mouse Select Operator
- * \{ */
-
-static bool uv_sticky_select(
- float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
-{
- int i;
-
- /* this function test if some vertex needs to selected
- * in addition to the existing ones due to sticky select */
- if (sticky == SI_STICKY_DISABLE) {
- return false;
- }
-
- for (i = 0; i < hitlen; i++) {
- if (hitv[i] == v) {
- if (sticky == SI_STICKY_LOC) {
- if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) {
- return true;
- }
- }
- else if (sticky == SI_STICKY_VERTEX) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static int uv_mouse_select_multi(bContext *C,
- Object **objects,
- uint objects_len,
- const float co[2],
- const bool extend,
- const bool deselect_all,
- const bool loop)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- UvNearestHit hit = UV_NEAREST_HIT_INIT;
- int i, selectmode, sticky, sync, *hitv = NULL;
- bool select = true;
- bool found_item = false;
- /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
- int flush = 0;
- int hitlen = 0;
- float limit[2], **hituv = NULL;
-
- /* notice 'limit' is the same no matter the zoom level, since this is like
- * remove doubles and could annoying if it joined points when zoomed out.
- * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
- * shift-selecting can consider an adjacent point close enough to add to
- * the selection rather than de-selecting the closest. */
-
- float penalty_dist;
- {
- float penalty[2];
- uvedit_pixel_to_float(sima, limit, 0.05f);
- uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
- penalty_dist = len_v2(penalty);
- }
-
- /* retrieve operation mode */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- sync = 1;
-
- if (ts->selectmode & SCE_SELECT_FACE) {
- selectmode = UV_SELECT_FACE;
- }
- else if (ts->selectmode & SCE_SELECT_EDGE) {
- selectmode = UV_SELECT_EDGE;
- }
- else {
- selectmode = UV_SELECT_VERTEX;
- }
-
- sticky = SI_STICKY_DISABLE;
- }
- else {
- sync = 0;
- selectmode = ts->uv_selectmode;
- sticky = (sima) ? sima->sticky : 1;
- }
-
- /* find nearest element */
- if (loop) {
- /* find edge */
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
- }
- else if (selectmode == UV_SELECT_VERTEX) {
- /* find vertex */
- found_item = uv_find_nearest_vert_multi(
- scene, ima, objects, objects_len, co, penalty_dist, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
-
- if (found_item) {
- /* mark 1 vertex as being hit */
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
-
- hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
- hituv[hit.lindex] = hit.luv->uv;
-
- hitlen = hit.efa->len;
- }
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* find edge */
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
-
- if (found_item) {
- /* mark 2 edge vertices as being hit */
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
-
- hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
- hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
- hituv[hit.lindex] = hit.luv->uv;
- hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
-
- hitlen = hit.efa->len;
- }
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* find face */
- found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
-
- if (found_item) {
- BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* make active */
- BM_mesh_active_face_set(em->bm, hit.efa);
-
- /* mark all face vertices as being hit */
-
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- hituv[i] = luv->uv;
- hitv[i] = BM_elem_index_get(l->v);
- }
-
- hitlen = hit.efa->len;
- }
- }
- else if (selectmode == UV_SELECT_ISLAND) {
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
- }
-
- if (!found_item) {
- if (deselect_all) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
-
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
- }
-
- Object *obedit = hit.ob;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do selection */
- if (loop) {
- if (!extend) {
- /* TODO(MULTI_EDIT): We only need to de-select non-active */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
- flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
- }
- else if (selectmode == UV_SELECT_ISLAND) {
- if (!extend) {
- /* TODO(MULTI_EDIT): We only need to de-select non-active */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
- /* Current behavior of 'extend'
- * is actually toggling, so pass extend flag as 'toggle' here */
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, false, false, extend, false);
- }
- else if (extend) {
- if (selectmode == UV_SELECT_VERTEX) {
- /* (de)select uv vertex */
- select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
- uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* (de)select edge */
- select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
- uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* (de)select face */
- select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
- uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset);
- flush = -1;
- }
-
- /* de-selecting an edge may deselect a face too - validate */
- if (sync) {
- if (select == false) {
- BM_select_history_validate(em->bm);
- }
- }
-
- /* (de)select sticky uv nodes */
- if (sticky != SI_STICKY_DISABLE) {
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uv_sticky_select(
- limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
-
- flush = select ? 1 : -1;
- }
- }
- else {
- /* deselect all */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
-
- if (selectmode == UV_SELECT_VERTEX) {
- /* select vertex */
- uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* select edge */
- uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* select face */
- uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset);
- }
-
- /* select sticky uvs */
- if (sticky != SI_STICKY_DISABLE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (sticky == SI_STICKY_DISABLE) {
- continue;
- }
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (uv_sticky_select(
- limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
- uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
- }
-
- flush = 1;
- }
- }
- }
- }
-
- if (sync) {
- /* flush for mesh selection */
-
- /* before bmesh */
-#if 0
- if (ts->selectmode != SCE_SELECT_FACE) {
- if (flush == 1) {
- EDBM_select_flush(em);
- }
- else if (flush == -1) {
- EDBM_deselect_flush(em);
- }
- }
-#else
- if (flush != 0) {
- if (loop) {
- /* push vertex -> edge selection */
- if (select) {
- EDBM_select_flush(em);
- }
- else {
- EDBM_deselect_flush(em);
- }
- }
- else {
- EDBM_selectmode_flush(em);
- }
- }
-#endif
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obiter = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obiter);
- }
-
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
-}
-static int uv_mouse_select(
- bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop)
-{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
- int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop);
- MEM_freeN(objects);
- return ret;
-}
-
-static int uv_select_exec(bContext *C, wmOperator *op)
-{
- float co[2];
-
- RNA_float_get_array(op->ptr, "location", co);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
- const bool loop = false;
-
- return uv_mouse_select(C, co, extend, deselect_all, loop);
-}
-
-static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- float co[2];
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
-
- return uv_select_exec(C, op);
-}
-
-static void UV_OT_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select";
- ot->description = "Select UV vertices";
- ot->idname = "UV_OT_select";
- ot->flag = OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_exec;
- ot->invoke = uv_select_invoke;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* properties */
- PropertyRNA *prop;
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- RNA_def_float_vector(
- ot->srna,
- "location",
- 2,
- NULL,
- -FLT_MAX,
- FLT_MAX,
- "Location",
- "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
- -100.0f,
- 100.0f);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Loop Select Operator
- * \{ */
-
-static int uv_select_loop_exec(bContext *C, wmOperator *op)
-{
- float co[2];
-
- RNA_float_get_array(op->ptr, "location", co);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = false;
- const bool loop = true;
-
- return uv_mouse_select(C, co, extend, deselect_all, loop);
-}
-
-static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- float co[2];
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
-
- return uv_select_loop_exec(C, op);
-}
-
-static void UV_OT_select_loop(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Loop Select";
- ot->description = "Select a loop of connected UV vertices";
- ot->idname = "UV_OT_select_loop";
- ot->flag = OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_loop_exec;
- ot->invoke = uv_select_loop_invoke;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* properties */
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- RNA_def_float_vector(
- ot->srna,
- "location",
- 2,
- NULL,
- -FLT_MAX,
- FLT_MAX,
- "Location",
- "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
- -100.0f,
- 100.0f);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Linked Operator
- * \{ */
-
-static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- float limit[2];
- bool extend = true;
- bool deselect = false;
- bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
-
- UvNearestHit hit = UV_NEAREST_HIT_INIT;
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Select linked only works in face select mode when sync selection is enabled");
- return OPERATOR_CANCELLED;
- }
-
- if (pick) {
- extend = RNA_boolean_get(op->ptr, "extend");
- deselect = RNA_boolean_get(op->ptr, "deselect");
- }
- uvedit_pixel_to_float(sima, limit, 0.05f);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- if (pick) {
- float co[2];
-
- if (event) {
- /* invoke */
- ARegion *region = CTX_wm_region(C);
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
- }
- else {
- /* exec */
- RNA_float_get_array(op->ptr, "location", co);
- }
-
- if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
- MEM_freeN(objects);
- return OPERATOR_CANCELLED;
- }
- }
-
- if (!extend) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- uv_select_linked_multi(scene,
- ima,
- objects,
- objects_len,
- limit,
- pick ? &hit : NULL,
- extend,
- deselect,
- false,
- select_faces);
-
- /* weak!, but works */
- Object **objects_free = objects;
- if (pick) {
- objects = &hit.ob;
- objects_len = 1;
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
-
- MEM_SAFE_FREE(objects_free);
-
- return OPERATOR_FINISHED;
-}
-
-static int uv_select_linked_exec(bContext *C, wmOperator *op)
-{
- return uv_select_linked_internal(C, op, NULL, false);
-}
-
-static void UV_OT_select_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Linked";
- ot->description = "Select all UV vertices linked to the active UV map";
- ot->idname = "UV_OT_select_linked";
-
- /* api callbacks */
- ot->exec = uv_select_linked_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Linked (Cursor Pick) Operator
- * \{ */
-
-static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- return uv_select_linked_internal(C, op, event, true);
-}
-
-static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
-{
- return uv_select_linked_internal(C, op, NULL, true);
-}
-
-static void UV_OT_select_linked_pick(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Linked Pick";
- ot->description = "Select all UV vertices linked under the mouse";
- ot->idname = "UV_OT_select_linked_pick";
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->invoke = uv_select_linked_pick_invoke;
- ot->exec = uv_select_linked_pick_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* properties */
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- RNA_def_boolean(ot->srna,
- "deselect",
- 0,
- "Deselect",
- "Deselect linked UV vertices rather than selecting them");
- RNA_def_float_vector(
- ot->srna,
- "location",
- 2,
- NULL,
- -FLT_MAX,
- FLT_MAX,
- "Location",
- "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
- -100.0f,
- 100.0f);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Split Operator
- * \{ */
-
-/**
- * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect
- * but in this case they are not joined to begin with (only having the behavior of being joined)
- * so its best to call this #uv_select_split() instead of just split(), but assigned to the same
- * key as #MESH_OT_split - Campbell.
- */
-static int uv_select_split_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
-
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
- return OPERATOR_CANCELLED;
- }
-
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- bool is_sel = false;
- bool is_unsel = false;
-
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- /* are we all selected? */
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- is_sel = true;
- }
- else {
- is_unsel = true;
- }
-
- /* we have mixed selection, bail out */
- if (is_sel && is_unsel) {
- break;
- }
- }
-
- if (is_sel && is_unsel) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
-
- changed = true;
- }
- }
-
- if (changed) {
- changed_multi = true;
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
-static void UV_OT_select_split(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Split";
- ot->description = "Select only entirely selected faces";
- ot->idname = "UV_OT_select_split";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_split_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
-}
-
-static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select)
-{
- /* bmesh API handles flushing but not on de-select */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode != SCE_SELECT_FACE) {
- if (select == false) {
- EDBM_deselect_flush(em);
- }
- else {
- EDBM_select_flush(em);
- }
- }
-
- if (select == false) {
- BM_select_history_validate(em->bm);
- }
- }
-}
-
-static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
- const ToolSettings *ts,
- Object *obedit)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
- }
- else {
- Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
- BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
- /* Only for region redraw. */
- WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select/Tag Flushing Utils
- *
- * Utility functions to flush the uv-selection from tags.
- * \{ */
-
-/**
- * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
- */
-static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene,
- BMEditMesh *em,
- UvVertMap *vmap,
- const uint efa_index,
- BMLoop *l,
- const bool select,
- const int cd_loop_uv_offset)
-{
- UvMapVert *start_vlist = NULL, *vlist_iter;
- BMFace *efa_vlist;
-
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
-
- vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- while (vlist_iter) {
- if (vlist_iter->separate) {
- start_vlist = vlist_iter;
- }
-
- if (efa_index == vlist_iter->poly_index) {
- break;
- }
-
- vlist_iter = vlist_iter->next;
- }
-
- vlist_iter = start_vlist;
- while (vlist_iter) {
-
- if (vlist_iter != start_vlist && vlist_iter->separate) {
- break;
- }
-
- if (efa_index != vlist_iter->poly_index) {
- BMLoop *l_other;
- efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
- /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
-
- l_other = BM_iter_at_index(
- em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
-
- uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset);
- }
- vlist_iter = vlist_iter->next;
- }
-}
-
-/**
- * Flush the selection from face tags based on sticky and selection modes.
- *
- * needed because settings the selection a face is done in a number of places but it also
- * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes
- * is best done in a separate function.
- *
- * \note This function is very similar to #uv_select_flush_from_tag_loop,
- * be sure to update both upon changing.
- */
-static void uv_select_flush_from_tag_face(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select)
-{
- /* Selecting UV Faces with some modes requires us to change
- * the selection in other faces (depending on the sticky mode).
- *
- * This only needs to be done when the Mesh is not used for
- * selection (so for sticky modes, vertex or location based). */
-
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
- /* Tag all verts as untouched, then touch the ones that have a face center
- * in the loop and select all MLoopUV's that use a touched vert. */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
-
- /* now select tagged verts */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
- else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
- struct UvVertMap *vmap;
- float limit[2];
- uint efa_index;
-
- uvedit_pixel_to_float(sima, limit, 0.05);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
- if (vmap == NULL) {
- return;
- }
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- uv_select_flush_from_tag_sticky_loc_internal(
- scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
- }
- }
- }
- BM_uv_vert_map_free(vmap);
- }
- else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
- }
- }
- }
-}
-
-/**
- * Flush the selection from loop tags based on sticky and selection modes.
- *
- * needed because settings the selection a face is done in a number of places but it also needs
- * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done
- * in a separate function.
- *
- * \note This function is very similar to #uv_select_flush_from_tag_loop,
- * be sure to update both upon changing.
- */
-static void uv_select_flush_from_tag_loop(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select)
-{
- /* Selecting UV Loops with some modes requires us to change
- * the selection in other faces (depending on the sticky mode).
- *
- * This only needs to be done when the Mesh is not used for
- * selection (so for sticky modes, vertex or location based). */
-
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
- /* Tag all verts as untouched, then touch the ones that have a face center
- * in the loop and select all MLoopUV's that use a touched vert. */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
-
- /* now select tagged verts */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
- else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
- struct UvVertMap *vmap;
- float limit[2];
- uint efa_index;
-
- uvedit_pixel_to_float(sima, limit, 0.05);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
- if (vmap == NULL) {
- return;
- }
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- uv_select_flush_from_tag_sticky_loc_internal(
- scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
- }
- }
- }
- BM_uv_vert_map_free(vmap);
- }
- else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
-}
-
-/** \} */
-
-#define UV_SELECT_ISLAND_LIMIT \
- float limit[2]; \
- uvedit_pixel_to_float(sima, limit, 0.05f)
-
-/* -------------------------------------------------------------------- */
-/** \name Box Select Operator
- * \{ */
-
-static int uv_box_select_exec(bContext *C, wmOperator *op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- ARegion *region = CTX_wm_region(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- rctf rectf;
- bool pinned;
- const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
-
- /* get rectangle from operator */
- WM_operator_properties_border_to_rctf(op, &rectf);
- UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
-
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- const bool select = (sel_op != SEL_OP_SUB);
- const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
-
- pinned = RNA_boolean_get(op->ptr, "pinned");
-
- UV_SELECT_ISLAND_LIMIT;
-
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- /* don't indent to avoid diff noise! */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do actual selection */
- if (use_face_center && !pinned) {
- /* handle face selection mode */
- float cent[2];
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* assume not touched */
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
-
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- if (BLI_rctf_isect_pt_v(&rectf, cent)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else {
- /* other selection modes */
- changed = true;
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- bool has_selected = false;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
- /* UV_SYNC_SELECTION - can't do pinned selection */
- if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- has_selected = true;
- }
- }
- else if (pinned) {
- if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
- }
- if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
- UvNearestHit hit = {
- .ob = obedit,
- .efa = efa,
- };
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed || use_pre_deselect) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
-
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
-static void UV_OT_select_box(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Box Select";
- ot->description = "Select UV vertices using box selection";
- ot->idname = "UV_OT_select_box";
-
- /* api callbacks */
- ot->invoke = WM_gesture_box_invoke;
- ot->exec = uv_box_select_exec;
- ot->modal = WM_gesture_box_modal;
- ot->poll = ED_operator_uvedit_space_image; /* requires space image */
- ot->cancel = WM_gesture_box_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
-
- WM_operator_properties_gesture_box(ot);
- WM_operator_properties_select_operation_simple(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Circle Select Operator
- * \{ */
-
-static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2])
-{
- /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
- float x, y;
- x = (uv[0] - offset[0]) * ellipse[0];
- y = (uv[1] - offset[1]) * ellipse[1];
- return ((x * x + y * y) < 1.0f);
-}
-
-static int uv_circle_select_exec(bContext *C, wmOperator *op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const ToolSettings *ts = scene->toolsettings;
- ARegion *region = CTX_wm_region(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- int x, y, radius, width, height;
- float zoomx, zoomy, offset[2], ellipse[2];
-
- const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
-
- /* get operator properties */
- x = RNA_int_get(op->ptr, "x");
- y = RNA_int_get(op->ptr, "y");
- radius = RNA_int_get(op->ptr, "radius");
-
- /* compute ellipse size and location, not a circle since we deal
- * with non square image. ellipse is normalized, r = 1.0. */
- ED_space_image_get_size(sima, &width, &height);
- ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
-
- ellipse[0] = width * zoomx / radius;
- ellipse[1] = height * zoomy / radius;
-
- UI_view2d_region_to_view(&region->v2d, x, y, &offset[0], &offset[1]);
-
- UV_SELECT_ISLAND_LIMIT;
-
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
- WM_gesture_is_modal_first(op->customdata));
- const bool select = (sel_op != SEL_OP_SUB);
- const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
-
- if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do selection */
- if (use_face_center) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- /* assume not touched */
- if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- if (uv_inside_circle(cent, offset, ellipse)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else {
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- bool has_selected = false;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uv_inside_circle(luv->uv, offset, ellipse)) {
- changed = true;
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- has_selected = true;
- }
- }
- }
- if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
- UvNearestHit hit = {
- .ob = obedit,
- .efa = efa,
- };
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed || use_pre_deselect) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
-static void UV_OT_select_circle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Circle Select";
- ot->description = "Select UV vertices using circle selection";
- ot->idname = "UV_OT_select_circle";
-
- /* api callbacks */
- ot->invoke = WM_gesture_circle_invoke;
- ot->modal = WM_gesture_circle_modal;
- ot->exec = uv_circle_select_exec;
- ot->poll = ED_operator_uvedit_space_image; /* requires space image */
- ot->cancel = WM_gesture_circle_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- WM_operator_properties_gesture_circle(ot);
- WM_operator_properties_select_operation_simple(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Lasso Select Operator
- * \{ */
-
-static bool do_lasso_select_mesh_uv(bContext *C,
- const int mcords[][2],
- short moves,
- const eSelectOp sel_op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- ARegion *region = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
- const bool select = (sel_op != SEL_OP_SUB);
- const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
-
- BMIter iter, liter;
-
- BMFace *efa;
- BMLoop *l;
- int screen_uv[2];
- bool changed_multi = false;
- rcti rect;
-
- UV_SELECT_ISLAND_LIMIT;
-
- BLI_lasso_boundbox(&rect, mcords, moves);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- /* don't indent to avoid diff noise! */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
-
- bool changed = false;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (use_face_center) { /* Face Center Sel */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- /* assume not touched */
- if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
-
- if (UI_view2d_view_to_region_clip(
- &region->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) &&
- BLI_rcti_isect_pt_v(&rect, screen_uv) &&
- BLI_lasso_is_point_inside(
- mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else { /* Vert Sel */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- bool has_selected = false;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UI_view2d_view_to_region_clip(
- &region->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) &&
- BLI_rcti_isect_pt_v(&rect, screen_uv) &&
- BLI_lasso_is_point_inside(
- mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- changed = true;
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- has_selected = true;
- }
- }
- }
- if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
- UvNearestHit hit = {
- .ob = obedit,
- .efa = efa,
- };
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed || use_pre_deselect) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi;
-}
-
-static int uv_lasso_select_exec(bContext *C, wmOperator *op)
-{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
-
- if (mcords) {
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op);
- MEM_freeN((void *)mcords);
-
- return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
- }
-
- return OPERATOR_PASS_THROUGH;
-}
-
-static void UV_OT_select_lasso(wmOperatorType *ot)
-{
- ot->name = "Lasso Select UV";
- ot->description = "Select UVs using lasso selection";
- ot->idname = "UV_OT_select_lasso";
-
- ot->invoke = WM_gesture_lasso_invoke;
- ot->modal = WM_gesture_lasso_modal;
- ot->exec = uv_lasso_select_exec;
- ot->poll = ED_operator_uvedit_space_image;
- ot->cancel = WM_gesture_lasso_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- WM_operator_properties_gesture_lasso(ot);
- WM_operator_properties_select_operation_simple(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Snap Cursor Operator
* \{ */
@@ -4379,314 +1473,6 @@ static void UV_OT_pin(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Select Pinned UV's Operator
- * \{ */
-
-static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- bool changed = false;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_PINNED) {
- uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
- changed = true;
- }
- }
- }
-
- if (changed) {
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static void UV_OT_select_pinned(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Selected Pinned";
- ot->description = "Select all pinned UV vertices";
- ot->idname = "UV_OT_select_pinned";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_pinned_exec;
- ot->poll = ED_operator_uvedit;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Overlap Operator
- * \{ */
-
-BLI_INLINE uint overlap_hash(const void *overlap_v)
-{
- const BVHTreeOverlap *overlap = overlap_v;
-
- /* Designed to treat (A,B) and (B,A) as the same. */
- int x = overlap->indexA;
- int y = overlap->indexB;
- if (x > y) {
- SWAP(int, x, y);
- }
- return BLI_hash_int_2d(x, y);
-}
-
-BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
-{
- const BVHTreeOverlap *a = a_v;
- const BVHTreeOverlap *b = b_v;
- return !((a->indexA == b->indexA && a->indexB == b->indexB) ||
- (a->indexA == b->indexB && a->indexB == b->indexA));
-}
-
-struct UVOverlapData {
- int ob_index;
- int face_index;
- float tri[3][2];
-};
-
-static int uv_select_overlap(bContext *C, const bool extend)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- /* Calculate maximum number of tree nodes and prepare initial selection. */
- uint uv_tri_len = 0;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
- if (!extend) {
- uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
- }
-
- BMIter iter;
- BMFace *efa;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) {
- continue;
- }
- uv_tri_len += efa->len - 2;
- }
- }
-
- struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len,
- "UvOverlapData");
- BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6);
-
- /* Use a global data index when inserting into the BVH. */
- int data_index = 0;
-
- int face_len_alloc = 3;
- float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords");
- uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris");
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* Triangulate each UV face and store it inside the BVH. */
- int face_index;
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
-
- if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) {
- continue;
- }
-
- const uint face_len = efa->len;
- const uint tri_len = face_len - 2;
-
- if (face_len_alloc < face_len) {
- MEM_freeN(uv_verts);
- MEM_freeN(indices);
- uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords");
- indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris");
- face_len_alloc = face_len;
- }
-
- int vert_index;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- copy_v2_v2(uv_verts[vert_index], luv->uv);
- }
-
- BLI_polyfill_calc(uv_verts, face_len, 0, indices);
-
- for (int t = 0; t < tri_len; t++) {
- overlap_data[data_index].ob_index = ob_index;
- overlap_data[data_index].face_index = face_index;
-
- /* BVH needs 3D, overlap data uses 2D. */
- const float tri[3][3] = {
- {UNPACK2(uv_verts[indices[t][0]]), 0.0f},
- {UNPACK2(uv_verts[indices[t][1]]), 0.0f},
- {UNPACK2(uv_verts[indices[t][2]]), 0.0f},
- };
-
- copy_v2_v2(overlap_data[data_index].tri[0], tri[0]);
- copy_v2_v2(overlap_data[data_index].tri[1], tri[1]);
- copy_v2_v2(overlap_data[data_index].tri[2], tri[2]);
-
- BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3);
- data_index++;
- }
- }
- }
- BLI_assert(data_index == uv_tri_len);
-
- MEM_freeN(uv_verts);
- MEM_freeN(indices);
-
- BLI_bvhtree_balance(uv_tree);
-
- uint tree_overlap_len;
- BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL);
-
- if (overlap != NULL) {
- GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len);
-
- for (int i = 0; i < tree_overlap_len; i++) {
- /* Skip overlaps against yourself. */
- if (overlap[i].indexA == overlap[i].indexB) {
- continue;
- }
-
- /* Skip overlaps that have already been tested. */
- if (!BLI_gset_add(overlap_set, &overlap[i])) {
- continue;
- }
-
- const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA];
- const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB];
- Object *obedit_a = objects[o_a->ob_index];
- Object *obedit_b = objects[o_b->ob_index];
- BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a);
- BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b);
- BMFace *face_a = em_a->bm->ftable[o_a->face_index];
- BMFace *face_b = em_b->bm->ftable[o_b->face_index];
- const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV);
- const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV);
-
- /* Skip if both faces are already selected. */
- if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) &&
- uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) {
- continue;
- }
-
- /* Main tri-tri overlap test. */
- const float endpoint_bias = -1e-4f;
- const float(*t1)[2] = o_a->tri;
- const float(*t2)[2] = o_b->tri;
- float vi[2];
- bool result = (
- /* Don't use 'isect_tri_tri_v2' here
- * because it's important to ignore overlap at end-points. */
- isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 ||
- isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 ||
- isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0);
-
- if (result) {
- uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a);
- uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b);
- }
- }
-
- BLI_gset_free(overlap_set, NULL);
- MEM_freeN(overlap);
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- uv_select_tag_update_for_object(depsgraph, scene->toolsettings, objects[ob_index]);
- }
-
- BLI_bvhtree_free(uv_tree);
-
- MEM_freeN(overlap_data);
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static int uv_select_overlap_exec(bContext *C, wmOperator *op)
-{
- bool extend = RNA_boolean_get(op->ptr, "extend");
- return uv_select_overlap(C, extend);
-}
-
-static void UV_OT_select_overlap(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Overlap";
- ot->description = "Select all UV faces which overlap each other";
- ot->idname = "UV_OT_select_overlap";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_overlap_exec;
- ot->poll = ED_operator_uvedit;
-
- /* properties */
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Hide Operator
* \{ */
@@ -5334,6 +2120,7 @@ static void UV_OT_mark_seam(wmOperatorType *ot)
void ED_operatortypes_uvedit(void)
{
+ /* uvedit_select.c */
WM_operatortype_append(UV_OT_select_all);
WM_operatortype_append(UV_OT_select);
WM_operatortype_append(UV_OT_select_loop);
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
new file mode 100644
index 00000000000..06866195c1c
--- /dev/null
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -0,0 +1,3415 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup eduv
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_image_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_lasso_2d.h"
+#include "BLI_math.h"
+#include "BLI_polyfill_2d.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "ED_image.h"
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_select_utils.h"
+#include "ED_uvedit.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_view2d.h"
+
+#include "uvedit_intern.h"
+
+static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action);
+static void uv_select_all_perform_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
+static void uv_select_flush_from_tag_face(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select);
+static void uv_select_flush_from_tag_loop(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select);
+static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
+ const ToolSettings *ts,
+ Object *obedit);
+
+/* -------------------------------------------------------------------- */
+/** \name Visibility and Selection Utilities
+ * \{ */
+
+static void uv_select_island_limit_default(SpaceImage *sima, float r_limit[2])
+{
+ uvedit_pixel_to_float(sima, 0.05f, r_limit);
+}
+
+static void uvedit_vertex_select_tagged(BMEditMesh *em,
+ Scene *scene,
+ bool select,
+ int cd_loop_uv_offset)
+{
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+}
+
+bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
+ }
+ else {
+ return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ }
+}
+bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa)
+{
+ return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa);
+}
+
+bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa)
+{
+ if (ts->uv_flag & UV_SHOW_SAME_IMAGE) {
+ Image *face_image;
+ ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL);
+ return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false;
+ }
+ else {
+ return uvedit_face_visible_nolocal_ex(ts, efa);
+ }
+}
+bool uvedit_face_visible_test(const Scene *scene, Object *obedit, Image *ima, BMFace *efa)
+{
+ return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa);
+}
+
+bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (!(luv->flag & MLOOPUV_VERTSEL)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
+{
+ return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
+}
+
+bool uvedit_face_select_set(const struct Scene *scene,
+ struct BMEditMesh *em,
+ struct BMFace *efa,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ if (select) {
+ return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
+ }
+ else {
+ return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
+}
+
+bool uvedit_face_select_enable(const Scene *scene,
+ BMEditMesh *em,
+ BMFace *efa,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BM_face_select_set(em->bm, efa, true);
+ if (do_history) {
+ BM_select_history_store(em->bm, (BMElem *)efa);
+ }
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool uvedit_face_select_disable(const Scene *scene,
+ BMEditMesh *em,
+ BMFace *efa,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BM_face_select_set(em->bm, efa, false);
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
+ }
+ else if (ts->selectmode == SCE_SELECT_EDGE) {
+ return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
+ }
+ else {
+ return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
+ }
+}
+bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+{
+ return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
+}
+
+void uvedit_edge_select_set(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+
+{
+ if (select) {
+ uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
+ }
+ else {
+ uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset);
+ }
+}
+
+void uvedit_edge_select_enable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ BM_face_select_set(em->bm, l->f, true);
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ BM_edge_select_set(em->bm, l->e, true);
+ }
+ else {
+ BM_vert_select_set(em->bm, l->e->v1, true);
+ BM_vert_select_set(em->bm, l->e->v2, true);
+ }
+
+ if (do_history) {
+ BM_select_history_store(em->bm, (BMElem *)l->e);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ luv1->flag |= MLOOPUV_VERTSEL;
+ luv2->flag |= MLOOPUV_VERTSEL;
+ }
+}
+
+void uvedit_edge_select_disable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const int cd_loop_uv_offset)
+
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ BM_face_select_set(em->bm, l->f, false);
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ BM_edge_select_set(em->bm, l->e, false);
+ }
+ else {
+ BM_vert_select_set(em->bm, l->e->v1, false);
+ BM_vert_select_set(em->bm, l->e->v2, false);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ luv1->flag &= ~MLOOPUV_VERTSEL;
+ luv2->flag &= ~MLOOPUV_VERTSEL;
+ }
+}
+
+bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
+ }
+ else {
+ return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
+ }
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ return (luv->flag & MLOOPUV_VERTSEL) != 0;
+ }
+}
+bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+{
+ return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
+}
+
+void uvedit_uv_select_set(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ if (select) {
+ uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
+ }
+ else {
+ uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset);
+ }
+}
+
+void uvedit_uv_select_enable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ BM_face_select_set(em->bm, l->f, true);
+ }
+ else {
+ BM_vert_select_set(em->bm, l->v, true);
+ }
+
+ if (do_history) {
+ BM_select_history_remove(em->bm, (BMElem *)l->v);
+ }
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+}
+
+void uvedit_uv_select_disable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ BM_face_select_set(em->bm, l->f, false);
+ }
+ else {
+ BM_vert_select_set(em->bm, l->v, false);
+ }
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Find Nearest Elements
+ * \{ */
+
+bool uv_find_nearest_edge(
+ Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv, *luv_next;
+ int i;
+ bool found = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
+
+ if (dist_test_sq < hit->dist_sq) {
+ hit->efa = efa;
+
+ hit->l = l;
+ hit->luv = luv;
+ hit->luv_next = luv_next;
+ hit->lindex = i;
+
+ hit->dist_sq = dist_test_sq;
+ found = true;
+ }
+ }
+ }
+ return found;
+}
+
+bool uv_find_nearest_edge_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
+bool uv_find_nearest_face(
+ Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool found = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* this will fill in hit.vert1 and hit.vert2 */
+ float dist_sq_init = hit_final->dist_sq;
+ UvNearestHit hit = *hit_final;
+ if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
+ hit.l = NULL;
+ hit.luv = hit.luv_next = NULL;
+
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+
+ const float dist_test_sq = len_squared_v2v2(co, cent);
+
+ if (dist_test_sq < hit.dist_sq) {
+ hit.efa = efa;
+ hit.dist_sq = dist_test_sq;
+ found = true;
+ }
+ }
+ }
+ if (found) {
+ *hit_final = hit;
+ }
+ return found;
+}
+
+bool uv_find_nearest_face_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
+static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
+{
+ const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
+ const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
+ const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
+
+ return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
+ (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
+}
+
+bool uv_find_nearest_vert(Scene *scene,
+ Image *ima,
+ Object *obedit,
+ float const co[2],
+ const float penalty_dist,
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+
+ /* this will fill in hit.vert1 and hit.vert2 */
+ float dist_sq_init = hit_final->dist_sq;
+ UvNearestHit hit = *hit_final;
+ if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
+
+ hit.l = NULL;
+ hit.luv = hit.luv_next = NULL;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter;
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BMIter liter;
+ BMLoop *l;
+ int i;
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ float dist_test_sq;
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
+ dist_test_sq = square_f(dist_test_sq);
+ }
+ else {
+ dist_test_sq = len_squared_v2v2(co, luv->uv);
+ }
+
+ if (dist_test_sq <= hit.dist_sq) {
+ if (dist_test_sq == hit.dist_sq) {
+ if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
+ continue;
+ }
+ }
+
+ hit.dist_sq = dist_test_sq;
+
+ hit.l = l;
+ hit.luv = luv;
+ hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ hit.efa = efa;
+ hit.lindex = i;
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (found) {
+ *hit_final = hit;
+ }
+
+ return found;
+}
+
+bool uv_find_nearest_vert_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len,
+ float const co[2],
+ const float penalty_dist,
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
+bool ED_uvedit_nearest_uv(const Scene *scene,
+ Object *obedit,
+ Image *ima,
+ const float co[2],
+ float *dist_sq,
+ float r_uv[2])
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMIter iter;
+ BMFace *efa;
+ const float *uv_best = NULL;
+ float dist_best = *dist_sq;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
+ const float dist_test = len_squared_v2v2(co, uv);
+ if (dist_best > dist_test) {
+ dist_best = dist_test;
+ uv_best = uv;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ if (uv_best != NULL) {
+ copy_v2_v2(r_uv, uv_best);
+ *dist_sq = dist_best;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool ED_uvedit_nearest_uv_multi(const Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ float *dist_sq,
+ float r_uv[2])
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) {
+ found = true;
+ }
+ }
+ return found;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Select
+ * \{ */
+
+static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
+{
+ UvMapVert *iterv;
+ int count = 0;
+
+ for (iterv = first; iterv; iterv = iterv->next) {
+ if (iterv->separate && iterv != first) {
+ break;
+ }
+
+ count++;
+ }
+
+ if (count < 5) {
+ first->flag = 1;
+ }
+}
+
+static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l)
+{
+ UvMapVert *iterv, *first;
+ first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ for (iterv = first; iterv; iterv = iterv->next) {
+ if (iterv->separate) {
+ first = iterv;
+ }
+ if (iterv->poly_index == BM_elem_index_get(efa)) {
+ return first;
+ }
+ }
+
+ return NULL;
+}
+
+static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em,
+ UvMapVert *first1,
+ UvMapVert *first2,
+ int *totface)
+{
+ UvMapVert *iterv1, *iterv2;
+ BMFace *efa;
+ int tot = 0;
+
+ /* count number of faces this edge has */
+ for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
+ if (iterv1->separate && iterv1 != first1) {
+ break;
+ }
+
+ for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
+ if (iterv2->separate && iterv2 != first2) {
+ break;
+ }
+
+ if (iterv1->poly_index == iterv2->poly_index) {
+ /* if face already tagged, don't do this edge */
+ efa = BM_face_at_index(em->bm, iterv1->poly_index);
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ return false;
+ }
+
+ tot++;
+ break;
+ }
+ }
+ }
+
+ if (*totface == 0) { /* start edge */
+ *totface = tot;
+ }
+ else if (tot != *totface) { /* check for same number of faces as start edge */
+ return false;
+ }
+
+ /* tag the faces */
+ for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
+ if (iterv1->separate && iterv1 != first1) {
+ break;
+ }
+
+ for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
+ if (iterv2->separate && iterv2 != first2) {
+ break;
+ }
+
+ if (iterv1->poly_index == iterv2->poly_index) {
+ efa = BM_face_at_index(em->bm, iterv1->poly_index);
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+static int uv_select_edgeloop(Scene *scene,
+ Image *ima,
+ Object *obedit,
+ UvNearestHit *hit,
+ const float limit[2],
+ const bool extend)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter, liter;
+ BMLoop *l;
+ UvVertMap *vmap;
+ UvMapVert *iterv_curr;
+ UvMapVert *iterv_next;
+ int starttotf;
+ bool looking, select;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* setup */
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
+
+ if (!extend) {
+ uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
+ }
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+
+ /* set flags for first face and verts */
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
+ iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
+ uv_select_edgeloop_vertex_loop_flag(iterv_curr);
+ uv_select_edgeloop_vertex_loop_flag(iterv_next);
+
+ starttotf = 0;
+ uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf);
+
+ /* sorry, first edge isn't even ok */
+ looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0);
+
+ /* iterate */
+ while (looking) {
+ looking = false;
+
+ /* find correct valence edges which are not tagged yet, but connect to tagged one */
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG) &&
+ uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ /* check face not hidden and not tagged */
+ if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) {
+ continue;
+ }
+ if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) {
+ continue;
+ }
+
+ /* check if vertex is tagged and has right valence */
+ if (iterv_curr->flag || iterv_next->flag) {
+ if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) {
+ looking = true;
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+
+ uv_select_edgeloop_vertex_loop_flag(iterv_curr);
+ uv_select_edgeloop_vertex_loop_flag(iterv_next);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* do the actual select/deselect */
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
+ iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
+ iterv_curr->flag = 1;
+ iterv_next->flag = 1;
+
+ if (extend) {
+ select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
+ }
+ else {
+ select = true;
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l);
+
+ if (iterv_curr->flag) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+
+ /* cleanup */
+ BM_uv_vert_map_free(vmap);
+
+ return (select) ? 1 : -1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked
+ * \{ */
+
+static void uv_select_linked_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len,
+ const float limit[2],
+ UvNearestHit *hit_final,
+ bool extend,
+ bool deselect,
+ bool toggle,
+ bool select_faces)
+{
+ /* loop over objects, or just use hit_final->ob */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (hit_final && ob_index != 0) {
+ break;
+ }
+ Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ UvVertMap *vmap;
+ UvMapVert *vlist, *iterv, *startv;
+ int i, stacksize = 0, *stack;
+ uint a;
+ char *flag;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
+
+ /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
+ * this made *every* projection split the island into front/back islands.
+ * Keep 'use_winding' to false, see: T50970.
+ *
+ * Better solve this by having a delimit option for select-linked operator,
+ * keeping island-select working as is. */
+ vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
+
+ if (vmap == NULL) {
+ continue;
+ }
+
+ stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
+ flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
+
+ if (hit_final == NULL) {
+ /* Use existing selection */
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (efa == hit_final->efa) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+ break;
+ }
+ }
+ }
+
+ while (stacksize > 0) {
+
+ stacksize--;
+ a = stack[stacksize];
+
+ efa = BM_face_at_index(em->bm, a);
+
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+
+ /* make_uv_vert_map_EM sets verts tmp.l to the indices */
+ vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ startv = vlist;
+
+ for (iterv = vlist; iterv; iterv = iterv->next) {
+ if (iterv->separate) {
+ startv = iterv;
+ }
+ if (iterv->poly_index == a) {
+ break;
+ }
+ }
+
+ for (iterv = startv; iterv; iterv = iterv->next) {
+ if ((startv != iterv) && (iterv->separate)) {
+ break;
+ }
+ else if (!flag[iterv->poly_index]) {
+ flag[iterv->poly_index] = 1;
+ stack[stacksize] = iterv->poly_index;
+ stacksize++;
+ }
+ }
+ }
+ }
+
+ /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
+ if ((toggle == true) && (extend == false) && (deselect == false)) {
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ bool found_selected = false;
+ if (!flag[a]) {
+ continue;
+ }
+
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ found_selected = true;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ found_selected = true;
+ }
+ }
+
+ if (found_selected) {
+ deselect = true;
+ break;
+ }
+ }
+ }
+ }
+
+#define SET_SELECTION(value) \
+ if (select_faces) { \
+ BM_face_select_set(em->bm, efa, value); \
+ } \
+ else { \
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
+ luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
+ } \
+ } \
+ (void)0
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (!flag[a]) {
+ if (!extend && !deselect && !toggle) {
+ SET_SELECTION(false);
+ }
+ continue;
+ }
+
+ if (!deselect) {
+ SET_SELECTION(true);
+ }
+ else {
+ SET_SELECTION(false);
+ }
+ }
+
+#undef SET_SELECTION
+
+ MEM_freeN(stack);
+ MEM_freeN(flag);
+ BM_uv_vert_map_free(vmap);
+ }
+}
+
+/**
+ * \warning This returns first selected UV,
+ * not ideal in many cases since there could be multiple.
+ */
+const float *uvedit_first_selected_uv_from_vertex(
+ Scene *scene, Object *obedit, Image *ima, BMVert *eve, const int cd_loop_uv_offset)
+{
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
+ continue;
+ }
+
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ return luv->uv;
+ }
+ }
+
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More/Less Operator
+ * \{ */
+
+static int uv_select_more_less(bContext *C, const bool select)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = CTX_data_edit_image(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ const ToolSettings *ts = scene->toolsettings;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (select) {
+ EDBM_select_more(em, true);
+ }
+ else {
+ EDBM_select_less(em, true);
+ }
+
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ continue;
+ }
+
+ if (is_uv_face_selectmode) {
+
+ /* clear tags */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+
+ /* mark loops to be selected */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+
+#define IS_SEL 1
+#define IS_UNSEL 2
+
+ int sel_state = 0;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ sel_state |= IS_SEL;
+ }
+ else {
+ sel_state |= IS_UNSEL;
+ }
+
+ /* if we have a mixed selection, tag to grow it */
+ if (sel_state == (IS_SEL | IS_UNSEL)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ break;
+ }
+ }
+
+#undef IS_SEL
+#undef IS_UNSEL
+ }
+ }
+ }
+ else {
+
+ /* clear tags */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_disable(l, BM_ELEM_TAG);
+ }
+ }
+
+ /* mark loops to be selected */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
+ BM_elem_flag_enable(l->next, BM_ELEM_TAG);
+ BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ if (is_uv_face_selectmode) {
+ /* Select tagged faces. */
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ else {
+ /* Select tagged loops. */
+ uv_select_flush_from_tag_loop(sima, scene, obedit, select);
+ }
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return uv_select_more_less(C, true);
+}
+
+void UV_OT_select_more(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select More";
+ ot->description = "Select more UV vertices connected to initial selection";
+ ot->idname = "UV_OT_select_more";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_more_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+}
+
+static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return uv_select_more_less(C, false);
+}
+
+void UV_OT_select_less(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Less";
+ ot->description = "Deselect UV vertices at the boundary of each selection region";
+ ot->idname = "UV_OT_select_less";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_less_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name (De)Select All Operator
+ * \{ */
+
+bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
+{
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
+ }
+ else {
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool uvedit_select_is_any_selected_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uvedit_select_is_any_selected(scene, ima, obedit)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
+{
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (action == SEL_TOGGLE) {
+ action = uvedit_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ switch (action) {
+ case SEL_TOGGLE:
+ EDBM_select_toggle_all(em);
+ break;
+ case SEL_SELECT:
+ EDBM_flag_enable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_DESELECT:
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_INVERT:
+ EDBM_select_swap(em);
+ EDBM_selectmode_flush(em);
+ break;
+ }
+ }
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ switch (action) {
+ case SEL_SELECT:
+ luv->flag |= MLOOPUV_VERTSEL;
+ break;
+ case SEL_DESELECT:
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ break;
+ case SEL_INVERT:
+ luv->flag ^= MLOOPUV_VERTSEL;
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void uv_select_all_perform_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
+{
+ if (action == SEL_TOGGLE) {
+ action = uvedit_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT :
+ SEL_SELECT;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_all_perform(scene, ima, obedit, action);
+ }
+}
+
+static int uv_select_all_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ Image *ima = CTX_data_edit_image(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ int action = RNA_enum_get(op->ptr, "action");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->description = "Change selection of all UV vertices";
+ ot->idname = "UV_OT_select_all";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_all_exec;
+ ot->poll = ED_operator_uvedit;
+
+ WM_operator_properties_select_all(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mouse Select Operator
+ * \{ */
+
+static bool uv_sticky_select(
+ float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
+{
+ int i;
+
+ /* this function test if some vertex needs to selected
+ * in addition to the existing ones due to sticky select */
+ if (sticky == SI_STICKY_DISABLE) {
+ return false;
+ }
+
+ for (i = 0; i < hitlen; i++) {
+ if (hitv[i] == v) {
+ if (sticky == SI_STICKY_LOC) {
+ if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) {
+ return true;
+ }
+ }
+ else if (sticky == SI_STICKY_VERTEX) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static int uv_mouse_select_multi(bContext *C,
+ Object **objects,
+ uint objects_len,
+ const float co[2],
+ const bool extend,
+ const bool deselect_all,
+ const bool loop)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ Image *ima = CTX_data_edit_image(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+ int i, selectmode, sticky, sync, *hitv = NULL;
+ bool select = true;
+ bool found_item = false;
+ /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ int flush = 0;
+ int hitlen = 0;
+ float limit[2], **hituv = NULL;
+
+ /* notice 'limit' is the same no matter the zoom level, since this is like
+ * remove doubles and could annoying if it joined points when zoomed out.
+ * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
+ * shift-selecting can consider an adjacent point close enough to add to
+ * the selection rather than de-selecting the closest. */
+
+ float penalty_dist;
+ {
+ float penalty[2];
+ uvedit_pixel_to_float(sima, 0.05f, limit);
+ uvedit_pixel_to_float(sima, 5.0f / (sima ? sima->zoom : 1.0f), penalty);
+ penalty_dist = len_v2(penalty);
+ }
+
+ /* retrieve operation mode */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ sync = 1;
+
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ selectmode = UV_SELECT_FACE;
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ selectmode = UV_SELECT_EDGE;
+ }
+ else {
+ selectmode = UV_SELECT_VERTEX;
+ }
+
+ sticky = SI_STICKY_DISABLE;
+ }
+ else {
+ sync = 0;
+ selectmode = ts->uv_selectmode;
+ sticky = (sima) ? sima->sticky : 1;
+ }
+
+ /* find nearest element */
+ if (loop) {
+ /* find edge */
+ found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
+ }
+ else if (selectmode == UV_SELECT_VERTEX) {
+ /* find vertex */
+ found_item = uv_find_nearest_vert_multi(
+ scene, ima, objects, objects_len, co, penalty_dist, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+
+ if (found_item) {
+ /* mark 1 vertex as being hit */
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+
+ hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
+ hituv[hit.lindex] = hit.luv->uv;
+
+ hitlen = hit.efa->len;
+ }
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* find edge */
+ found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+
+ if (found_item) {
+ /* mark 2 edge vertices as being hit */
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+
+ hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
+ hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
+ hituv[hit.lindex] = hit.luv->uv;
+ hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
+
+ hitlen = hit.efa->len;
+ }
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* find face */
+ found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+
+ if (found_item) {
+ BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* make active */
+ BM_mesh_active_face_set(em->bm, hit.efa);
+
+ /* mark all face vertices as being hit */
+
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ hituv[i] = luv->uv;
+ hitv[i] = BM_elem_index_get(l->v);
+ }
+
+ hitlen = hit.efa->len;
+ }
+ }
+ else if (selectmode == UV_SELECT_ISLAND) {
+ found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+ }
+
+ if (!found_item) {
+ if (deselect_all) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *obedit = hit.ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do selection */
+ if (loop) {
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+ flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
+ }
+ else if (selectmode == UV_SELECT_ISLAND) {
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+ /* Current behavior of 'extend'
+ * is actually toggling, so pass extend flag as 'toggle' here */
+ uv_select_linked_multi(
+ scene, ima, objects, objects_len, limit, &hit, false, false, extend, false);
+ }
+ else if (extend) {
+ if (selectmode == UV_SELECT_VERTEX) {
+ /* (de)select uv vertex */
+ select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* (de)select edge */
+ select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
+ uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* (de)select face */
+ select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
+ uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset);
+ flush = -1;
+ }
+
+ /* de-selecting an edge may deselect a face too - validate */
+ if (sync) {
+ if (select == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
+
+ /* (de)select sticky uv nodes */
+ if (sticky != SI_STICKY_DISABLE) {
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (uv_sticky_select(
+ limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+
+ flush = select ? 1 : -1;
+ }
+ }
+ else {
+ /* deselect all */
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+
+ if (selectmode == UV_SELECT_VERTEX) {
+ /* select vertex */
+ uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* select edge */
+ uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* select face */
+ uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset);
+ }
+
+ /* select sticky uvs */
+ if (sticky != SI_STICKY_DISABLE) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (sticky == SI_STICKY_DISABLE) {
+ continue;
+ }
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (uv_sticky_select(
+ limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
+ uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
+ }
+
+ flush = 1;
+ }
+ }
+ }
+ }
+
+ if (sync) {
+ /* flush for mesh selection */
+
+ /* before bmesh */
+#if 0
+ if (ts->selectmode != SCE_SELECT_FACE) {
+ if (flush == 1) {
+ EDBM_select_flush(em);
+ }
+ else if (flush == -1) {
+ EDBM_deselect_flush(em);
+ }
+ }
+#else
+ if (flush != 0) {
+ if (loop) {
+ /* push vertex -> edge selection */
+ if (select) {
+ EDBM_select_flush(em);
+ }
+ else {
+ EDBM_deselect_flush(em);
+ }
+ }
+ else {
+ EDBM_selectmode_flush(em);
+ }
+ }
+#endif
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obiter = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obiter);
+ }
+
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+}
+static int uv_mouse_select(
+ bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+ int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop);
+ MEM_freeN(objects);
+ return ret;
+}
+
+static int uv_select_exec(bContext *C, wmOperator *op)
+{
+ float co[2];
+
+ RNA_float_get_array(op->ptr, "location", co);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ const bool loop = false;
+
+ return uv_mouse_select(C, co, extend, deselect_all, loop);
+}
+
+static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const ARegion *region = CTX_wm_region(C);
+ float co[2];
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+
+ return uv_select_exec(C, op);
+}
+
+void UV_OT_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select";
+ ot->description = "Select UV vertices";
+ ot->idname = "UV_OT_select";
+ ot->flag = OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_exec;
+ ot->invoke = uv_select_invoke;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* properties */
+ PropertyRNA *prop;
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ prop = RNA_def_boolean(ot->srna,
+ "deselect_all",
+ false,
+ "Deselect On Nothing",
+ "Deselect all when nothing under the cursor");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Select Operator
+ * \{ */
+
+static int uv_select_loop_exec(bContext *C, wmOperator *op)
+{
+ float co[2];
+
+ RNA_float_get_array(op->ptr, "location", co);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool deselect_all = false;
+ const bool loop = true;
+
+ return uv_mouse_select(C, co, extend, deselect_all, loop);
+}
+
+static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const ARegion *region = CTX_wm_region(C);
+ float co[2];
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+
+ return uv_select_loop_exec(C, op);
+}
+
+void UV_OT_select_loop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Loop Select";
+ ot->description = "Select a loop of connected UV vertices";
+ ot->idname = "UV_OT_select_loop";
+ ot->flag = OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_loop_exec;
+ ot->invoke = uv_select_loop_invoke;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ * \{ */
+
+static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = CTX_data_edit_image(C);
+ float limit[2];
+ bool extend = true;
+ bool deselect = false;
+ bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
+
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Select linked only works in face select mode when sync selection is enabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (pick) {
+ extend = RNA_boolean_get(op->ptr, "extend");
+ deselect = RNA_boolean_get(op->ptr, "deselect");
+ }
+ uv_select_island_limit_default(sima, limit);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (pick) {
+ float co[2];
+
+ if (event) {
+ /* invoke */
+ const ARegion *region = CTX_wm_region(C);
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+ }
+ else {
+ /* exec */
+ RNA_float_get_array(op->ptr, "location", co);
+ }
+
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (!extend) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+
+ uv_select_linked_multi(scene,
+ ima,
+ objects,
+ objects_len,
+ limit,
+ pick ? &hit : NULL,
+ extend,
+ deselect,
+ false,
+ select_faces);
+
+ /* weak!, but works */
+ Object **objects_free = objects;
+ if (pick) {
+ objects = &hit.ob;
+ objects_len = 1;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_SAFE_FREE(objects_free);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_linked_exec(bContext *C, wmOperator *op)
+{
+ return uv_select_linked_internal(C, op, NULL, false);
+}
+
+void UV_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked";
+ ot->description = "Select all UV vertices linked to the active UV map";
+ ot->idname = "UV_OT_select_linked";
+
+ /* api callbacks */
+ ot->exec = uv_select_linked_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked (Cursor Pick) Operator
+ * \{ */
+
+static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ return uv_select_linked_internal(C, op, event, true);
+}
+
+static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
+{
+ return uv_select_linked_internal(C, op, NULL, true);
+}
+
+void UV_OT_select_linked_pick(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked Pick";
+ ot->description = "Select all UV vertices linked under the mouse";
+ ot->idname = "UV_OT_select_linked_pick";
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->invoke = uv_select_linked_pick_invoke;
+ ot->exec = uv_select_linked_pick_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ RNA_def_boolean(ot->srna,
+ "deselect",
+ 0,
+ "Deselect",
+ "Deselect linked UV vertices rather than selecting them");
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Split Operator
+ * \{ */
+
+/**
+ * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect
+ * but in this case they are not joined to begin with (only having the behavior of being joined)
+ * so its best to call this #uv_select_split() instead of just split(), but assigned to the same
+ * key as #MESH_OT_split - Campbell.
+ */
+static int uv_select_split_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const ToolSettings *ts = scene->toolsettings;
+ Image *ima = CTX_data_edit_image(C);
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ bool is_sel = false;
+ bool is_unsel = false;
+
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ /* are we all selected? */
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ is_sel = true;
+ }
+ else {
+ is_unsel = true;
+ }
+
+ /* we have mixed selection, bail out */
+ if (is_sel && is_unsel) {
+ break;
+ }
+ }
+
+ if (is_sel && is_unsel) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ changed_multi = true;
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void UV_OT_select_split(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Split";
+ ot->description = "Select only entirely selected faces";
+ ot->idname = "UV_OT_select_split";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_split_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+}
+
+static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select)
+{
+ /* bmesh API handles flushing but not on de-select */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode != SCE_SELECT_FACE) {
+ if (select == false) {
+ EDBM_deselect_flush(em);
+ }
+ else {
+ EDBM_select_flush(em);
+ }
+ }
+
+ if (select == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
+}
+
+static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
+ const ToolSettings *ts,
+ Object *obedit)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
+ else {
+ Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
+ BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
+ /* Only for region redraw. */
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select/Tag Flushing Utils
+ *
+ * Utility functions to flush the uv-selection from tags.
+ * \{ */
+
+/**
+ * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
+ */
+static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene,
+ BMEditMesh *em,
+ UvVertMap *vmap,
+ const uint efa_index,
+ BMLoop *l,
+ const bool select,
+ const int cd_loop_uv_offset)
+{
+ UvMapVert *start_vlist = NULL, *vlist_iter;
+ BMFace *efa_vlist;
+
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+
+ vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ while (vlist_iter) {
+ if (vlist_iter->separate) {
+ start_vlist = vlist_iter;
+ }
+
+ if (efa_index == vlist_iter->poly_index) {
+ break;
+ }
+
+ vlist_iter = vlist_iter->next;
+ }
+
+ vlist_iter = start_vlist;
+ while (vlist_iter) {
+
+ if (vlist_iter != start_vlist && vlist_iter->separate) {
+ break;
+ }
+
+ if (efa_index != vlist_iter->poly_index) {
+ BMLoop *l_other;
+ efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
+ /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
+
+ l_other = BM_iter_at_index(
+ em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
+
+ uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset);
+ }
+ vlist_iter = vlist_iter->next;
+ }
+}
+
+/**
+ * Flush the selection from face tags based on sticky and selection modes.
+ *
+ * needed because settings the selection a face is done in a number of places but it also
+ * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes
+ * is best done in a separate function.
+ *
+ * \note This function is very similar to #uv_select_flush_from_tag_loop,
+ * be sure to update both upon changing.
+ */
+static void uv_select_flush_from_tag_face(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select)
+{
+ /* Selecting UV Faces with some modes requires us to change
+ * the selection in other faces (depending on the sticky mode).
+ *
+ * This only needs to be done when the Mesh is not used for
+ * selection (so for sticky modes, vertex or location based). */
+
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
+ /* Tag all verts as untouched, then touch the ones that have a face center
+ * in the loop and select all MLoopUV's that use a touched vert. */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* now select tagged verts */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+ else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
+ struct UvVertMap *vmap;
+ float limit[2];
+ uint efa_index;
+
+ uv_select_island_limit_default(sima, limit);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+ if (vmap == NULL) {
+ return;
+ }
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ uv_select_flush_from_tag_sticky_loc_internal(
+ scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
+ }
+ }
+ }
+ BM_uv_vert_map_free(vmap);
+ }
+ else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+}
+
+/**
+ * Flush the selection from loop tags based on sticky and selection modes.
+ *
+ * needed because settings the selection a face is done in a number of places but it also needs
+ * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done
+ * in a separate function.
+ *
+ * \note This function is very similar to #uv_select_flush_from_tag_loop,
+ * be sure to update both upon changing.
+ */
+static void uv_select_flush_from_tag_loop(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select)
+{
+ /* Selecting UV Loops with some modes requires us to change
+ * the selection in other faces (depending on the sticky mode).
+ *
+ * This only needs to be done when the Mesh is not used for
+ * selection (so for sticky modes, vertex or location based). */
+
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
+ /* Tag all verts as untouched, then touch the ones that have a face center
+ * in the loop and select all MLoopUV's that use a touched vert. */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* now select tagged verts */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+ else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
+ struct UvVertMap *vmap;
+ float limit[2];
+ uint efa_index;
+
+ uv_select_island_limit_default(sima, limit);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+ if (vmap == NULL) {
+ return;
+ }
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ uv_select_flush_from_tag_sticky_loc_internal(
+ scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
+ }
+ }
+ }
+ BM_uv_vert_map_free(vmap);
+ }
+ else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Box Select Operator
+ * \{ */
+
+static int uv_box_select_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = CTX_data_edit_image(C);
+ const ARegion *region = CTX_wm_region(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ rctf rectf;
+ bool pinned;
+ float limit[2];
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+ const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_EDGE) :
+ (ts->uv_selectmode == UV_SELECT_EDGE));
+
+ /* get rectangle from operator */
+ WM_operator_properties_border_to_rctf(op, &rectf);
+ UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
+
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
+
+ pinned = RNA_boolean_get(op->ptr, "pinned");
+
+ uv_select_island_limit_default(sima, limit);
+
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (use_pre_deselect) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do actual selection */
+ if (use_face_center && !pinned) {
+ /* handle face selection mode */
+ float cent[2];
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* assume not touched */
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (BLI_rctf_isect_pt_v(&rectf, cent)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else if (use_edge && !pinned) {
+ changed = true;
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+ bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if ((select != luv_select) || (select != luv_select_prev)) {
+ if (BLI_rctf_isect_pt_v(&rectf, luv->uv) &&
+ BLI_rctf_isect_pt_v(&rectf, luv_prev->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG);
+ }
+ }
+ l_prev = l;
+ luv_prev = luv;
+ luv_select_prev = luv_select;
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+ else {
+ /* other selection modes */
+ changed = true;
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ bool has_selected = false;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
+ /* UV_SYNC_SELECTION - can't do pinned selection */
+ if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ has_selected = true;
+ }
+ }
+ else if (pinned) {
+ if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
+ UvNearestHit hit = {
+ .ob = obedit,
+ .efa = efa,
+ };
+ uv_select_linked_multi(
+ scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed || use_pre_deselect) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void UV_OT_select_box(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Box Select";
+ ot->description = "Select UV vertices using box selection";
+ ot->idname = "UV_OT_select_box";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = uv_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->poll = ED_operator_uvedit_space_image; /* requires space image */
+ ot->cancel = WM_gesture_box_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
+
+ WM_operator_properties_gesture_box(ot);
+ WM_operator_properties_select_operation_simple(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Circle Select Operator
+ * \{ */
+
+static int uv_circle_select_is_point_inside(const float uv[2],
+ const float offset[2],
+ const float ellipse[2])
+{
+ /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
+ const float co[2] = {
+ (uv[0] - offset[0]) * ellipse[0],
+ (uv[1] - offset[1]) * ellipse[1],
+ };
+ return len_squared_v2(co) < 1.0f;
+}
+
+static int uv_circle_select_is_edge_inside(const float uv_a[2],
+ const float uv_b[2],
+ const float offset[2],
+ const float ellipse[2])
+{
+ /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
+ const float co_a[2] = {
+ (uv_a[0] - offset[0]) * ellipse[0],
+ (uv_a[1] - offset[1]) * ellipse[1],
+ };
+ const float co_b[2] = {
+ (uv_b[0] - offset[0]) * ellipse[0],
+ (uv_b[1] - offset[1]) * ellipse[1],
+ };
+ return dist_squared_to_line_segment_v2((const float[2]){0.0f, 0.0f}, co_a, co_b) < 1.0f;
+}
+
+static int uv_circle_select_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const ToolSettings *ts = scene->toolsettings;
+ const ARegion *region = CTX_wm_region(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ int x, y, radius, width, height;
+ float zoomx, zoomy;
+ float limit[2], offset[2], ellipse[2];
+
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+ const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_EDGE) :
+ (ts->uv_selectmode == UV_SELECT_EDGE));
+
+ /* get operator properties */
+ x = RNA_int_get(op->ptr, "x");
+ y = RNA_int_get(op->ptr, "y");
+ radius = RNA_int_get(op->ptr, "radius");
+
+ /* compute ellipse size and location, not a circle since we deal
+ * with non square image. ellipse is normalized, r = 1.0. */
+ ED_space_image_get_size(sima, &width, &height);
+ ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
+
+ ellipse[0] = width * zoomx / radius;
+ ellipse[1] = height * zoomy / radius;
+
+ UI_view2d_region_to_view(&region->v2d, x, y, &offset[0], &offset[1]);
+
+ uv_select_island_limit_default(sima, limit);
+
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
+ WM_gesture_is_modal_first(op->customdata));
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
+
+ if (use_pre_deselect) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do selection */
+ if (use_face_center) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* assume not touched */
+ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (uv_circle_select_is_point_inside(cent, offset, ellipse)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else if (use_edge) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+ bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if ((select != luv_select) || (select != luv_select_prev)) {
+ if (uv_circle_select_is_edge_inside(luv->uv, luv_prev->uv, offset, ellipse)) {
+ changed = true;
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG);
+ }
+ }
+ l_prev = l;
+ luv_prev = luv;
+ luv_select_prev = luv_select;
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+ else {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ bool has_selected = false;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) {
+ changed = true;
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ has_selected = true;
+ }
+ }
+ }
+ if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
+ UvNearestHit hit = {
+ .ob = obedit,
+ .efa = efa,
+ };
+ uv_select_linked_multi(
+ scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed || use_pre_deselect) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void UV_OT_select_circle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Circle Select";
+ ot->description = "Select UV vertices using circle selection";
+ ot->idname = "UV_OT_select_circle";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = uv_circle_select_exec;
+ ot->poll = ED_operator_uvedit_space_image; /* requires space image */
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_gesture_circle(ot);
+ WM_operator_properties_select_operation_simple(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lasso Select Operator
+ * \{ */
+
+static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region,
+ const rcti *clip_rect,
+ const int mcoords[][2],
+ const int mcoords_len,
+ const float co_test[2])
+{
+ int co_screen[2];
+ if (UI_view2d_view_to_region_clip(
+ &region->v2d, co_test[0], co_test[1], &co_screen[0], &co_screen[1]) &&
+ BLI_rcti_isect_pt_v(clip_rect, co_screen) &&
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, co_screen[0], co_screen[1], V2D_IS_CLIPPED)) {
+ return true;
+ }
+ return false;
+}
+
+static bool do_lasso_select_mesh_uv(bContext *C,
+ const int mcoords[][2],
+ short mcoords_len,
+ const eSelectOp sel_op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ const ARegion *region = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+ const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_EDGE) :
+ (ts->uv_selectmode == UV_SELECT_EDGE));
+
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
+
+ BMIter iter, liter;
+
+ BMFace *efa;
+ BMLoop *l;
+ float limit[2];
+ bool changed_multi = false;
+ rcti rect;
+
+ uv_select_island_limit_default(sima, limit);
+
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (use_pre_deselect) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
+ bool changed = false;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (use_face_center) { /* Face Center Sel */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* assume not touched */
+ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else if (use_edge) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+ bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if ((select != luv_select) || (select != luv_select_prev)) {
+ if (do_lasso_select_mesh_uv_is_point_inside(
+ region, &rect, mcoords, mcoords_len, luv->uv) &&
+ do_lasso_select_mesh_uv_is_point_inside(
+ region, &rect, mcoords, mcoords_len, luv_prev->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset);
+ changed = true;
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG);
+ }
+ }
+ l_prev = l;
+ luv_prev = luv;
+ luv_select_prev = luv_select;
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+ else { /* Vert Sel */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ bool has_selected = false;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (do_lasso_select_mesh_uv_is_point_inside(
+ region, &rect, mcoords, mcoords_len, luv->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ has_selected = true;
+ }
+ }
+ }
+ if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
+ UvNearestHit hit = {
+ .ob = obedit,
+ .efa = efa,
+ };
+ uv_select_linked_multi(
+ scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed || use_pre_deselect) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi;
+}
+
+static int uv_lasso_select_exec(bContext *C, wmOperator *op)
+{
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
+
+ if (mcoords) {
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ bool changed = do_lasso_select_mesh_uv(C, mcoords, mcoords_len, sel_op);
+ MEM_freeN((void *)mcoords);
+
+ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void UV_OT_select_lasso(wmOperatorType *ot)
+{
+ ot->name = "Lasso Select UV";
+ ot->description = "Select UVs using lasso selection";
+ ot->idname = "UV_OT_select_lasso";
+
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = uv_lasso_select_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_gesture_lasso(ot);
+ WM_operator_properties_select_operation_simple(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Pinned UV's Operator
+ * \{ */
+
+static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = CTX_data_edit_image(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ bool changed = false;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_PINNED) {
+ uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_select_pinned(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Selected Pinned";
+ ot->description = "Select all pinned UV vertices";
+ ot->idname = "UV_OT_select_pinned";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_pinned_exec;
+ ot->poll = ED_operator_uvedit;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Overlap Operator
+ * \{ */
+
+BLI_INLINE uint overlap_hash(const void *overlap_v)
+{
+ const BVHTreeOverlap *overlap = overlap_v;
+
+ /* Designed to treat (A,B) and (B,A) as the same. */
+ int x = overlap->indexA;
+ int y = overlap->indexB;
+ if (x > y) {
+ SWAP(int, x, y);
+ }
+ return BLI_hash_int_2d(x, y);
+}
+
+BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
+{
+ const BVHTreeOverlap *a = a_v;
+ const BVHTreeOverlap *b = b_v;
+ return !((a->indexA == b->indexA && a->indexB == b->indexB) ||
+ (a->indexA == b->indexB && a->indexB == b->indexA));
+}
+
+struct UVOverlapData {
+ int ob_index;
+ int face_index;
+ float tri[3][2];
+};
+
+static int uv_select_overlap(bContext *C, const bool extend)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = CTX_data_edit_image(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ /* Calculate maximum number of tree nodes and prepare initial selection. */
+ uint uv_tri_len = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+ if (!extend) {
+ uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
+ }
+
+ BMIter iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) {
+ continue;
+ }
+ uv_tri_len += efa->len - 2;
+ }
+ }
+
+ struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len,
+ "UvOverlapData");
+ BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6);
+
+ /* Use a global data index when inserting into the BVH. */
+ int data_index = 0;
+
+ int face_len_alloc = 3;
+ float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords");
+ uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris");
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* Triangulate each UV face and store it inside the BVH. */
+ int face_index;
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
+
+ if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) {
+ continue;
+ }
+
+ const uint face_len = efa->len;
+ const uint tri_len = face_len - 2;
+
+ if (face_len_alloc < face_len) {
+ MEM_freeN(uv_verts);
+ MEM_freeN(indices);
+ uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords");
+ indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris");
+ face_len_alloc = face_len;
+ }
+
+ int vert_index;
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(uv_verts[vert_index], luv->uv);
+ }
+
+ BLI_polyfill_calc(uv_verts, face_len, 0, indices);
+
+ for (int t = 0; t < tri_len; t++) {
+ overlap_data[data_index].ob_index = ob_index;
+ overlap_data[data_index].face_index = face_index;
+
+ /* BVH needs 3D, overlap data uses 2D. */
+ const float tri[3][3] = {
+ {UNPACK2(uv_verts[indices[t][0]]), 0.0f},
+ {UNPACK2(uv_verts[indices[t][1]]), 0.0f},
+ {UNPACK2(uv_verts[indices[t][2]]), 0.0f},
+ };
+
+ copy_v2_v2(overlap_data[data_index].tri[0], tri[0]);
+ copy_v2_v2(overlap_data[data_index].tri[1], tri[1]);
+ copy_v2_v2(overlap_data[data_index].tri[2], tri[2]);
+
+ BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3);
+ data_index++;
+ }
+ }
+ }
+ BLI_assert(data_index == uv_tri_len);
+
+ MEM_freeN(uv_verts);
+ MEM_freeN(indices);
+
+ BLI_bvhtree_balance(uv_tree);
+
+ uint tree_overlap_len;
+ BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL);
+
+ if (overlap != NULL) {
+ GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len);
+
+ for (int i = 0; i < tree_overlap_len; i++) {
+ /* Skip overlaps against yourself. */
+ if (overlap[i].indexA == overlap[i].indexB) {
+ continue;
+ }
+
+ /* Skip overlaps that have already been tested. */
+ if (!BLI_gset_add(overlap_set, &overlap[i])) {
+ continue;
+ }
+
+ const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA];
+ const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB];
+ Object *obedit_a = objects[o_a->ob_index];
+ Object *obedit_b = objects[o_b->ob_index];
+ BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a);
+ BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b);
+ BMFace *face_a = em_a->bm->ftable[o_a->face_index];
+ BMFace *face_b = em_b->bm->ftable[o_b->face_index];
+ const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV);
+
+ /* Skip if both faces are already selected. */
+ if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) &&
+ uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) {
+ continue;
+ }
+
+ /* Main tri-tri overlap test. */
+ const float endpoint_bias = -1e-4f;
+ const float(*t1)[2] = o_a->tri;
+ const float(*t2)[2] = o_b->tri;
+ float vi[2];
+ bool result = (
+ /* Don't use 'isect_tri_tri_v2' here
+ * because it's important to ignore overlap at end-points. */
+ isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 ||
+ isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 ||
+ isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0);
+
+ if (result) {
+ uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a);
+ uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b);
+ }
+ }
+
+ BLI_gset_free(overlap_set, NULL);
+ MEM_freeN(overlap);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ uv_select_tag_update_for_object(depsgraph, scene->toolsettings, objects[ob_index]);
+ }
+
+ BLI_bvhtree_free(uv_tree);
+
+ MEM_freeN(overlap_data);
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_overlap_exec(bContext *C, wmOperator *op)
+{
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ return uv_select_overlap(C, extend);
+}
+
+void UV_OT_select_overlap(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Overlap";
+ ot->description = "Select all UV faces which overlap each other";
+ ot->idname = "UV_OT_select_overlap";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_overlap_exec;
+ ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+}
+
+/** \} */
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 87743911add..d3c85b891c6 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -56,6 +56,7 @@ set(SRC
intern/MOD_gpencilsimplify.c
intern/MOD_gpencilsmooth.c
intern/MOD_gpencilsubdiv.c
+ intern/MOD_gpenciltexture.c
intern/MOD_gpencilthick.c
intern/MOD_gpenciltime.c
intern/MOD_gpenciltint.c
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
index f5c064c1c07..a7a4333d82e 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -43,6 +43,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_Offset;
extern GpencilModifierTypeInfo modifierType_Gpencil_Armature;
extern GpencilModifierTypeInfo modifierType_Gpencil_Time;
extern GpencilModifierTypeInfo modifierType_Gpencil_Multiply;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Texture;
/* MOD_gpencil_util.c */
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 7df0440aa85..f7b51b08c44 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -72,6 +72,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
INIT_GP_TYPE(Armature);
INIT_GP_TYPE(Time);
INIT_GP_TYPE(Multiply);
+ INIT_GP_TYPE(Texture);
#undef INIT_GP_TYPE
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
new file mode 100644
index 00000000000..15e069fc162
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
@@ -0,0 +1,165 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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, Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_util.h"
+
+static void initData(GpencilModifierData *md)
+{
+ TextureGpencilModifierData *gpmd = (TextureGpencilModifierData *)md;
+ gpmd->fit_method = GP_TEX_CONSTANT_LENGTH;
+ gpmd->fill_rotation = 0.0f;
+ gpmd->fill_scale = 1.0f;
+ gpmd->fill_offset[0] = 0.0f;
+ gpmd->fill_offset[1] = 0.0f;
+ gpmd->uv_offset = 0.0f;
+ gpmd->uv_scale = 1.0f;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->materialname[0] = '\0';
+ gpmd->vgname[0] = '\0';
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* change stroke uv texture values */
+static void deformStroke(GpencilModifierData *md,
+ Depsgraph *UNUSED(depsgraph),
+ Object *ob,
+ bGPDlayer *gpl,
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps)
+{
+ TextureGpencilModifierData *mmd = (TextureGpencilModifierData *)md;
+ const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->materialname,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 1,
+ gpl,
+ gps,
+ mmd->flag & GP_TEX_INVERT_LAYER,
+ mmd->flag & GP_TEX_INVERT_PASS,
+ mmd->flag & GP_TEX_INVERT_LAYERPASS,
+ mmd->flag & GP_TEX_INVERT_MATERIAL)) {
+ return;
+ }
+ if ((mmd->mode == FILL) || (mmd->mode == STROKE_AND_FILL)) {
+ gps->uv_rotation += mmd->fill_rotation;
+ gps->uv_translation[0] += mmd->fill_offset[0];
+ gps->uv_translation[1] += mmd->fill_offset[1];
+ gps->uv_scale *= mmd->fill_scale;
+ BKE_gpencil_stroke_geometry_update(gps);
+ }
+
+ if ((mmd->mode == STROKE) || (mmd->mode == STROKE_AND_FILL)) {
+ float totlen = 1.0f;
+ if (mmd->fit_method == GP_TEX_FIT_STROKE) {
+ totlen = 0.0f;
+ for (int i = 1; i < gps->totpoints; i++) {
+ totlen += len_v3v3(&gps->points[i - 1].x, &gps->points[i].x);
+ }
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+ /* Verify point is part of vertex group. */
+ float weight = get_modifier_point_weight(
+ dvert, (mmd->flag & GP_TEX_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ continue;
+ }
+
+ pt->uv_fac /= totlen;
+ pt->uv_fac *= mmd->uv_scale;
+ pt->uv_fac += mmd->uv_offset;
+ }
+ }
+}
+
+static void bakeModifier(struct Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ deformStroke(md, depsgraph, ob, gpl, gpf, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Texture = {
+ /* name */ "Texture Mapping",
+ /* structName */ "TextureGpencilModifierData",
+ /* structSize */ sizeof(TextureGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h
index 1cf6475408f..47b44b59461 100644
--- a/source/blender/gpu/GPU_immediate_util.h
+++ b/source/blender/gpu/GPU_immediate_util.h
@@ -70,6 +70,13 @@ void imm_draw_disk_partial_fill_2d(uint pos,
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2);
void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2);
+void imm_draw_box_checker_2d_ex(float x1,
+ float y1,
+ float x2,
+ float y2,
+ const float color_primary[4],
+ const float color_secondary[4],
+ int checker_size);
void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2);
void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]);
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index dd64b858b35..0e382f2225f 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -29,9 +29,9 @@ extern "C" {
#endif
typedef struct GPUShader GPUShader;
+struct GPUShaderInterface;
struct GPUTexture;
struct GPUUniformBuffer;
-struct GPUShaderInterface;
/* GPU Shader
* - only for fragment shaders now
diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c
index 7bcb0a7a552..d95904c0007 100644
--- a/source/blender/gpu/intern/gpu_immediate.c
+++ b/source/blender/gpu/intern/gpu_immediate.c
@@ -272,6 +272,14 @@ void immBegin(GPUPrimType prim_type, uint vertex_len)
/* printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); */
+#if TRUST_NO_ONE
+ {
+ GLint bufsize;
+ glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bufsize);
+ assert(active_buffer->buffer_offset + bytes_needed <= bufsize);
+ }
+#endif
+
active_buffer->buffer_data = glMapBufferRange(
GL_ARRAY_BUFFER,
active_buffer->buffer_offset,
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index 7266f595447..77b6f237f03 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -361,25 +361,35 @@ void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2)
/**
* Draw a standard checkerboard to indicate transparent backgrounds.
*/
-void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2)
+void imm_draw_box_checker_2d_ex(float x1,
+ float y1,
+ float x2,
+ float y2,
+ const float color_primary[4],
+ const float color_secondary[4],
+ const int checker_size)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- float checker_primary[4];
- float checker_secondary[4];
- int checker_size = UI_GetThemeValue(TH_TRANSPARENT_CHECKER_SIZE);
immBindBuiltinProgram(GPU_SHADER_2D_CHECKER);
- UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_PRIMARY, checker_primary);
- UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_SECONDARY, checker_secondary);
- immUniform4fv("color1", checker_primary);
- immUniform4fv("color2", checker_secondary);
+ immUniform4fv("color1", color_primary);
+ immUniform4fv("color2", color_secondary);
immUniform1i("size", checker_size);
immRectf(pos, x1, y1, x2, y2);
immUnbindProgram();
}
+void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2)
+{
+ float checker_primary[4];
+ float checker_secondary[4];
+ UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_PRIMARY, checker_primary);
+ UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_SECONDARY, checker_secondary);
+ int checker_size = UI_GetThemeValue(TH_TRANSPARENT_CHECKER_SIZE);
+ imm_draw_box_checker_2d_ex(x1, y1, x2, y2, checker_primary, checker_secondary, checker_size);
+}
void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3])
{
diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c
index cb1cd9a6f6d..1caa88d18ae 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.c
+++ b/source/blender/gpu/intern/gpu_shader_interface.c
@@ -254,8 +254,12 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
}
/* TODO: reject DOUBLE gl_types */
-
input->location = glGetAttribLocation(program, name);
+ /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */
+ if (input->location == -1) {
+ MEM_freeN(input);
+ continue;
+ }
shaderface->enabled_attr_mask |= (1 << input->location);
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index 496e8981f2b..f30270b9eed 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -559,10 +559,10 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport,
{
/**
* HACK(fclem): We copy the settings here to avoid use after free if an update frees the scene
- * and the viewport stays cached (see T75443). But this means the OCIO curvemapping caching
- * (which is based on CurveMap pointer address) cannot operate correctly and it will create
- * a different OCIO processor for each viewport. We try to only realloc the curvemap copy if
- * needed to avoid uneeded cache invalidation.
+ * and the viewport stays cached (see T75443). But this means the OCIO curve-mapping caching
+ * (which is based on #CurveMap pointer address) cannot operate correctly and it will create
+ * a different OCIO processor for each viewport. We try to only reallocate the curve-map copy
+ * if needed to avoid unneeded cache invalidation.
*/
if (view_settings->curve_mapping) {
if (viewport->view_settings.curve_mapping) {
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index aa82487d69f..7ebbd1a7409 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -338,9 +338,9 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, in
/*********************** Threaded image processing *************************/
-static void processor_apply_func(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid))
+static void processor_apply_func(TaskPool *__restrict pool, void *taskdata)
{
- void (*do_thread)(void *) = (void (*)(void *))BLI_task_pool_userdata(pool);
+ void (*do_thread)(void *) = (void (*)(void *))BLI_task_pool_user_data(pool);
do_thread(taskdata);
}
@@ -353,14 +353,13 @@ void IMB_processor_apply_threaded(
{
const int lines_per_task = 64;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
void *handles;
int total_tasks = (buffer_lines + lines_per_task - 1) / lines_per_task;
int i, start_line;
- task_pool = BLI_task_pool_create(task_scheduler, do_thread, TASK_PRIORITY_LOW);
+ task_pool = BLI_task_pool_create(do_thread, TASK_PRIORITY_LOW);
handles = MEM_callocN(handle_size * total_tasks, "processor apply threaded handles");
@@ -399,11 +398,9 @@ typedef struct ScanlineGlobalData {
int total_scanlines;
} ScanlineGlobalData;
-static void processor_apply_scanline_func(TaskPool *__restrict pool,
- void *taskdata,
- int UNUSED(threadid))
+static void processor_apply_scanline_func(TaskPool *__restrict pool, void *taskdata)
{
- ScanlineGlobalData *data = BLI_task_pool_userdata(pool);
+ ScanlineGlobalData *data = BLI_task_pool_user_data(pool);
int start_scanline = POINTER_AS_INT(taskdata);
int num_scanlines = min_ii(data->scanlines_per_task, data->total_scanlines - start_scanline);
data->do_thread(data->custom_data, start_scanline, num_scanlines);
@@ -420,8 +417,7 @@ void IMB_processor_apply_threaded_scanlines(int total_scanlines,
data.scanlines_per_task = scanlines_per_task;
data.total_scanlines = total_scanlines;
const int total_tasks = (total_scanlines + scanlines_per_task - 1) / scanlines_per_task;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &data, TASK_PRIORITY_LOW);
+ TaskPool *task_pool = BLI_task_pool_create(&data, TASK_PRIORITY_LOW);
for (int i = 0, start_line = 0; i < total_tasks; i++) {
BLI_task_pool_push(
task_pool, processor_apply_scanline_func, POINTER_FROM_INT(start_line), false, NULL);
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 5230cb050f4..289f8c7a7b9 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -436,6 +436,7 @@ typedef enum ID_Type {
ID_HA = MAKE_ID2('H', 'A'), /* Hair */
ID_PT = MAKE_ID2('P', 'T'), /* PointCloud */
ID_VO = MAKE_ID2('V', 'O'), /* Volume */
+ ID_SIM = MAKE_ID2('S', 'I'), /* Simulation */
} ID_Type;
/* Only used as 'placeholder' in .blend files for directly linked data-blocks. */
@@ -564,9 +565,9 @@ enum {
/* RESET_NEVER tag data-block as needing an auto-override execution, if enabled. */
LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH = 1 << 17,
- /* tag data-block has having an extra user. */
+ /* tag data-block as having an extra user. */
LIB_TAG_EXTRAUSER = 1 << 2,
- /* tag data-block has having actually increased usercount for the extra virtual user. */
+ /* tag data-block as having actually increased usercount for the extra virtual user. */
LIB_TAG_EXTRAUSER_SET = 1 << 7,
/* RESET_AFTER_USE tag newly duplicated/copied IDs.
@@ -735,6 +736,7 @@ typedef enum IDRecalcFlag {
#define FILTER_ID_HA (1ULL << 32)
#define FILTER_ID_PT (1ULL << 33)
#define FILTER_ID_VO (1ULL << 34)
+#define FILTER_ID_SIM (1ULL << 35)
#define FILTER_ID_ALL \
(FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | FILTER_ID_GD | \
@@ -742,7 +744,7 @@ typedef enum IDRecalcFlag {
FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | \
FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO | \
FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS | \
- FILTER_ID_LP | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO)
+ FILTER_ID_LP | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO | FILTER_ID_SIM)
/* IMPORTANT: this enum matches the order currently use in set_listbasepointers,
* keep them in sync! */
@@ -786,6 +788,7 @@ enum {
INDEX_ID_WS,
INDEX_ID_WM,
INDEX_ID_MSK,
+ INDEX_ID_SIM,
INDEX_ID_NULL,
INDEX_ID_MAX,
};
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index b29816c735b..635c155dec6 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -261,23 +261,23 @@ typedef enum eBone_InheritScaleMode {
/* Inherit all scale and shear. */
BONE_INHERIT_SCALE_FULL = 0,
/* Inherit scale, but remove final shear. */
- BONE_INHERIT_SCALE_FIX_SHEAR,
+ BONE_INHERIT_SCALE_FIX_SHEAR = 1,
/* Inherit average scale. */
- BONE_INHERIT_SCALE_AVERAGE,
+ BONE_INHERIT_SCALE_AVERAGE = 2,
/* Inherit no scale or shear. */
- BONE_INHERIT_SCALE_NONE,
+ BONE_INHERIT_SCALE_NONE = 3,
/* Inherit effects of shear on parent (same as old disabled Inherit Scale). */
- BONE_INHERIT_SCALE_NONE_LEGACY,
+ BONE_INHERIT_SCALE_NONE_LEGACY = 4,
/* Inherit parent X scale as child X scale etc. */
- BONE_INHERIT_SCALE_ALIGNED,
+ BONE_INHERIT_SCALE_ALIGNED = 5,
} eBone_InheritScaleMode;
/* bone->bbone_prev_type, bbone_next_type */
typedef enum eBone_BBoneHandleType {
- BBONE_HANDLE_AUTO = 0, /* Default mode based on parents & children. */
- BBONE_HANDLE_ABSOLUTE, /* Custom handle in absolute position mode. */
- BBONE_HANDLE_RELATIVE, /* Custom handle in relative position mode. */
- BBONE_HANDLE_TANGENT, /* Custom handle in tangent mode (use direction, not location). */
+ BBONE_HANDLE_AUTO = 0, /* Default mode based on parents & children. */
+ BBONE_HANDLE_ABSOLUTE = 1, /* Custom handle in absolute position mode. */
+ BBONE_HANDLE_RELATIVE = 2, /* Custom handle in relative position mode. */
+ BBONE_HANDLE_TANGENT = 3, /* Custom handle in tangent mode (use direction, not location). */
} eBone_BBoneHandleType;
#define MAXBONENAME 64
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 041943bc5e4..0e16abf76f7 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -805,8 +805,8 @@ typedef enum {
/* blur kernel types, Brush.blur_mode */
typedef enum eBlurKernelType {
- KERNEL_GAUSSIAN,
- KERNEL_BOX,
+ KERNEL_GAUSSIAN = 0,
+ KERNEL_BOX = 1,
} eBlurKernelType;
/* Brush.falloff_shape */
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 9efd2116601..65087a6d459 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -735,11 +735,11 @@ typedef enum eConstraint_EulerOrder {
/** Explicit euler rotation modes - must sync with BLI_math_rotation.h defines. */
CONSTRAINT_EULER_XYZ = 1,
- CONSTRAINT_EULER_XZY,
- CONSTRAINT_EULER_YXZ,
- CONSTRAINT_EULER_YZX,
- CONSTRAINT_EULER_ZXY,
- CONSTRAINT_EULER_ZYX,
+ CONSTRAINT_EULER_XZY = 2,
+ CONSTRAINT_EULER_YXZ = 3,
+ CONSTRAINT_EULER_YZX = 4,
+ CONSTRAINT_EULER_ZXY = 5,
+ CONSTRAINT_EULER_ZYX = 6,
} eConstraint_EulerOrder;
/* -------------------------------------- */
@@ -762,13 +762,13 @@ typedef enum eCopyRotation_MixMode {
/* Replace rotation channel values. */
ROTLIKE_MIX_REPLACE = 0,
/* Legacy Offset mode - don't use. */
- ROTLIKE_MIX_OFFSET,
+ ROTLIKE_MIX_OFFSET = 1,
/* Add Euler components together. */
- ROTLIKE_MIX_ADD,
+ ROTLIKE_MIX_ADD = 2,
/* Multiply the copied rotation on the left. */
- ROTLIKE_MIX_BEFORE,
+ ROTLIKE_MIX_BEFORE = 3,
/* Multiply the copied rotation on the right. */
- ROTLIKE_MIX_AFTER,
+ ROTLIKE_MIX_AFTER = 4,
} eCopyRotation_MixMode;
/* bLocateLikeConstraint.flag */
@@ -799,9 +799,9 @@ typedef enum eCopyTransforms_MixMode {
/* Replace rotation channel values. */
TRANSLIKE_MIX_REPLACE = 0,
/* Multiply the copied transformation on the left, with anti-shear scale handling. */
- TRANSLIKE_MIX_BEFORE,
+ TRANSLIKE_MIX_BEFORE = 1,
/* Multiply the copied transformation on the right, with anti-shear scale handling. */
- TRANSLIKE_MIX_AFTER,
+ TRANSLIKE_MIX_AFTER = 2,
} eCopyTransforms_MixMode;
/* bTransformConstraint.to/from */
@@ -816,7 +816,7 @@ typedef enum eTransform_MixModeLoc {
/* Add component values together (default). */
TRANS_MIXLOC_ADD = 0,
/* Replace component values. */
- TRANS_MIXLOC_REPLACE,
+ TRANS_MIXLOC_REPLACE = 1,
} eTransform_MixModeLoc;
/* bTransformConstraint.mix_mode_rot */
@@ -824,11 +824,11 @@ typedef enum eTransform_MixModeRot {
/* Add component values together (default). */
TRANS_MIXROT_ADD = 0,
/* Replace component values. */
- TRANS_MIXROT_REPLACE,
+ TRANS_MIXROT_REPLACE = 1,
/* Multiply the generated rotation on the left. */
- TRANS_MIXROT_BEFORE,
+ TRANS_MIXROT_BEFORE = 2,
/* Multiply the generated rotation on the right. */
- TRANS_MIXROT_AFTER,
+ TRANS_MIXROT_AFTER = 3,
} eTransform_MixModeRot;
/* bTransformConstraint.mix_mode_scale */
@@ -836,7 +836,7 @@ typedef enum eTransform_MixModeScale {
/* Replace component values (default). */
TRANS_MIXSCALE_REPLACE = 0,
/* Multiply component values together. */
- TRANS_MIXSCALE_MULTIPLY,
+ TRANS_MIXSCALE_MULTIPLY = 1,
} eTransform_MixModeScale;
/* bSameVolumeConstraint.free_axis */
@@ -867,9 +867,9 @@ typedef enum eActionConstraint_MixMode {
/* Multiply the action transformation on the right. */
ACTCON_MIX_AFTER_FULL = 0,
/* Multiply the action transformation on the right, with anti-shear scale handling. */
- ACTCON_MIX_AFTER,
+ ACTCON_MIX_AFTER = 1,
/* Multiply the action transformation on the left, with anti-shear scale handling. */
- ACTCON_MIX_BEFORE,
+ ACTCON_MIX_BEFORE = 2,
} eActionConstraint_MixMode;
/* Locked-Axis Values (Locked Track) */
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index c3425826d36..deb955f5551 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -47,6 +47,8 @@ typedef enum GpencilModifierType {
eGpencilModifierType_Armature = 15,
eGpencilModifierType_Time = 16,
eGpencilModifierType_Multiply = 17,
+ eGpencilModifierType_Texture = 18,
+ /* Keep last. */
NUM_GREASEPENCIL_MODIFIER_TYPES,
} GpencilModifierType;
@@ -713,4 +715,50 @@ typedef enum eTintGpencil_Flag {
GP_TINT_CUSTOM_CURVE = (1 << 6),
} eTintGpencil_Flag;
+typedef struct TextureGpencilModifierData {
+ GpencilModifierData modifier;
+ /** Layer name. */
+ char layername[64];
+ /** Material name. */
+ char materialname[64];
+ /** Optional vertexgroup name, MAX_VGROUP_NAME. */
+ char vgname[64];
+ /** Custom index for passes. */
+ int pass_index;
+ /** Flags. */
+ int flag;
+ /** Offset value to add to uv_fac. */
+ float uv_offset;
+ float uv_scale;
+ float fill_rotation;
+ float fill_offset[2];
+ float fill_scale;
+ /** Custom index for passes. */
+ int layer_pass;
+ /** Texture fit options. */
+ short fit_method;
+ short mode;
+} TextureGpencilModifierData;
+
+typedef enum eTextureGpencil_Flag {
+ GP_TEX_INVERT_LAYER = (1 << 0),
+ GP_TEX_INVERT_PASS = (1 << 1),
+ GP_TEX_INVERT_VGROUP = (1 << 2),
+ GP_TEX_INVERT_LAYERPASS = (1 << 3),
+ GP_TEX_INVERT_MATERIAL = (1 << 4),
+} eTextureGpencil_Flag;
+
+/* Texture->fit_method */
+typedef enum eTextureGpencil_Fit {
+ GP_TEX_FIT_STROKE = 0,
+ GP_TEX_CONSTANT_LENGTH = 1,
+} eTextureGpencil_Fit;
+
+/* Texture->mode */
+typedef enum eTextureGpencil_Mode {
+ STROKE = 0,
+ FILL = 1,
+ STROKE_AND_FILL = 2,
+} eTextureGpencil_Mode;
+
#endif /* __DNA_GPENCIL_MODIFIER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index d3d7ca1cc3b..bf9f228b53f 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -276,6 +276,7 @@ typedef enum eGPDstroke_Caps {
GP_STROKE_CAP_ROUND = 0,
GP_STROKE_CAP_FLAT = 1,
+ /* Keeo last. */
GP_STROKE_CAP_MAX,
} GPDstroke_Caps;
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 4676e7fa313..ef129a92699 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -115,6 +115,7 @@ typedef struct ViewLayer {
ListBase object_bases;
/** Default allocated now. */
struct SceneStats *stats;
+ char footer_str[128];
struct Base *basact;
/** A view layer has one top level layer collection, because a scene has only one top level
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 10a549edc17..357c3260121 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -324,35 +324,35 @@ enum {
/* blend_shadow */
enum {
MA_BS_NONE = 0,
- MA_BS_SOLID,
- MA_BS_CLIP,
- MA_BS_HASHED,
+ MA_BS_SOLID = 1,
+ MA_BS_CLIP = 2,
+ MA_BS_HASHED = 3,
};
/* Grease Pencil Stroke styles */
enum {
GP_MATERIAL_STROKE_STYLE_SOLID = 0,
- GP_MATERIAL_STROKE_STYLE_TEXTURE,
+ GP_MATERIAL_STROKE_STYLE_TEXTURE = 1,
};
/* Grease Pencil Fill styles */
enum {
GP_MATERIAL_FILL_STYLE_SOLID = 0,
- GP_MATERIAL_FILL_STYLE_GRADIENT,
- GP_MATERIAL_FILL_STYLE_CHECKER, /* DEPRECATED (only for convert old files) */
- GP_MATERIAL_FILL_STYLE_TEXTURE,
+ GP_MATERIAL_FILL_STYLE_GRADIENT = 1,
+ GP_MATERIAL_FILL_STYLE_CHECKER = 2, /* DEPRECATED (only for convert old files) */
+ GP_MATERIAL_FILL_STYLE_TEXTURE = 3,
};
/* Grease Pencil Gradient Types */
enum {
GP_MATERIAL_GRADIENT_LINEAR = 0,
- GP_MATERIAL_GRADIENT_RADIAL,
+ GP_MATERIAL_GRADIENT_RADIAL = 1,
};
/* Grease Pencil Follow Drawing Modes */
enum {
GP_MATERIAL_FOLLOW_PATH = 0,
- GP_MATERIAL_FOLLOW_OBJ,
- GP_MATERIAL_FOLLOW_FIXED,
+ GP_MATERIAL_FOLLOW_OBJ = 1,
+ GP_MATERIAL_FOLLOW_FIXED = 2,
};
#endif
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 9e58d7df042..8e7dc1fa266 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -452,23 +452,23 @@ enum {
/* BevelModifierData->face_str_mode */
enum {
- MOD_BEVEL_FACE_STRENGTH_NONE,
- MOD_BEVEL_FACE_STRENGTH_NEW,
- MOD_BEVEL_FACE_STRENGTH_AFFECTED,
- MOD_BEVEL_FACE_STRENGTH_ALL,
+ MOD_BEVEL_FACE_STRENGTH_NONE = 0,
+ MOD_BEVEL_FACE_STRENGTH_NEW = 1,
+ MOD_BEVEL_FACE_STRENGTH_AFFECTED = 2,
+ MOD_BEVEL_FACE_STRENGTH_ALL = 3,
};
/* BevelModifier->miter_inner and ->miter_outer */
enum {
- MOD_BEVEL_MITER_SHARP,
- MOD_BEVEL_MITER_PATCH,
- MOD_BEVEL_MITER_ARC,
+ MOD_BEVEL_MITER_SHARP = 0,
+ MOD_BEVEL_MITER_PATCH = 1,
+ MOD_BEVEL_MITER_ARC = 2,
};
/* BevelModifier->vmesh_method */
enum {
- MOD_BEVEL_VMESH_ADJ,
- MOD_BEVEL_VMESH_CUTOFF,
+ MOD_BEVEL_VMESH_ADJ = 0,
+ MOD_BEVEL_VMESH_CUTOFF = 1,
};
typedef struct FluidModifierData {
@@ -594,10 +594,10 @@ enum {
};
enum {
- MOD_DECIM_MODE_COLLAPSE,
- MOD_DECIM_MODE_UNSUBDIV,
+ MOD_DECIM_MODE_COLLAPSE = 0,
+ MOD_DECIM_MODE_UNSUBDIV = 1,
/** called planar in the UI */
- MOD_DECIM_MODE_DISSOLVE,
+ MOD_DECIM_MODE_DISSOLVE = 2,
};
typedef struct SmoothModifierData {
@@ -1694,15 +1694,15 @@ enum {
/* Triangulate methods - NGons */
enum {
MOD_TRIANGULATE_NGON_BEAUTY = 0,
- MOD_TRIANGULATE_NGON_EARCLIP,
+ MOD_TRIANGULATE_NGON_EARCLIP = 1,
};
/* Triangulate methods - Quads */
enum {
MOD_TRIANGULATE_QUAD_BEAUTY = 0,
- MOD_TRIANGULATE_QUAD_FIXED,
- MOD_TRIANGULATE_QUAD_ALTERNATE,
- MOD_TRIANGULATE_QUAD_SHORTEDGE,
+ MOD_TRIANGULATE_QUAD_FIXED = 1,
+ MOD_TRIANGULATE_QUAD_ALTERNATE = 2,
+ MOD_TRIANGULATE_QUAD_SHORTEDGE = 3,
};
typedef struct LaplacianSmoothModifierData {
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 8029e8ebc13..4ff0e531168 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -154,6 +154,12 @@ typedef enum eNodeSocketDatatype {
__SOCK_MESH = 5, /* deprecated */
SOCK_INT = 6,
SOCK_STRING = 7,
+ SOCK_OBJECT = 8,
+ SOCK_IMAGE = 9,
+ SOCK_EMITTERS = 10,
+ SOCK_EVENTS = 11,
+ SOCK_FORCES = 12,
+ SOCK_CONTROL_FLOW = 13,
} eNodeSocketDatatype;
/* socket shape */
@@ -498,6 +504,7 @@ typedef struct bNodeTree {
#define NTREE_SHADER 0
#define NTREE_COMPOSIT 1
#define NTREE_TEXTURE 2
+#define NTREE_SIMULATION 3
/* ntree->init, flag */
#define NTREE_TYPE_INIT 1
@@ -565,6 +572,14 @@ typedef struct bNodeSocketValueString {
char value[1024];
} bNodeSocketValueString;
+typedef struct bNodeSocketValueObject {
+ struct Object *value;
+} bNodeSocketValueObject;
+
+typedef struct bNodeSocketValueImage {
+ struct Image *value;
+} bNodeSocketValueImage;
+
/* data structs, for node->storage */
enum {
CMP_NODE_MASKTYPE_ADD = 0,
@@ -1293,6 +1308,23 @@ enum {
NODE_VECTOR_MATH_TANGENT = 23,
};
+/* Boolean math node operations. */
+enum {
+ NODE_BOOLEAN_MATH_AND = 0,
+ NODE_BOOLEAN_MATH_OR = 1,
+ NODE_BOOLEAN_MATH_NOT = 2,
+};
+
+/* Float compare node operations. */
+enum {
+ NODE_FLOAT_COMPARE_LESS_THAN = 0,
+ NODE_FLOAT_COMPARE_LESS_EQUAL = 1,
+ NODE_FLOAT_COMPARE_GREATER_THAN = 2,
+ NODE_FLOAT_COMPARE_GREATER_EQUAL = 3,
+ NODE_FLOAT_COMPARE_EQUAL = 4,
+ NODE_FLOAT_COMPARE_NOT_EQUAL = 5,
+};
+
/* Clamp node types. */
enum {
NODE_CLAMP_MINMAX = 0,
@@ -1385,4 +1417,16 @@ typedef enum NodeShaderOutputTarget {
SHD_OUTPUT_CYCLES = 2,
} NodeShaderOutputTarget;
+/* Particle Time Step Event node */
+typedef enum NodeSimParticleTimeStepEventType {
+ NODE_PARTICLE_TIME_STEP_EVENT_BEGIN = 0,
+ NODE_PARTICLE_TIME_STEP_EVENT_END = 1,
+} NodeSimParticleTimeStepEventType;
+
+/* Simulation Time node */
+typedef enum NodeSimInputTimeType {
+ NODE_SIM_INPUT_SIMULATION_TIME = 0,
+ NODE_SIM_INPUT_SCENE_TIME = 1,
+} NodeSimInputTimeType;
+
#endif
diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h
index 88c712b5b28..daa3a629d27 100644
--- a/source/blender/makesdna/DNA_object_force_types.h
+++ b/source/blender/makesdna/DNA_object_force_types.h
@@ -62,6 +62,7 @@ typedef enum ePFieldType {
/** Force based on smoke simulation air flow. */
PFIELD_SMOKEFLOW = 13,
+ /* Keep last. */
NUM_PFIELD_TYPES,
} ePFieldType;
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 1a76d32dc2c..47e6db835c9 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -462,6 +462,7 @@ enum {
OB_VOLUME = 29,
+ /* Keep last. */
OB_TYPE_MAX,
};
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index f4834355223..357c1158b47 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -99,19 +99,19 @@ typedef struct AviCodecData {
} AviCodecData;
typedef enum eFFMpegPreset {
- FFM_PRESET_NONE,
+ FFM_PRESET_NONE = 0,
#ifdef DNA_DEPRECATED_ALLOW
/* Previously used by h.264 to control encoding speed vs. file size. */
- FFM_PRESET_ULTRAFAST, /* DEPRECATED */
- FFM_PRESET_SUPERFAST, /* DEPRECATED */
- FFM_PRESET_VERYFAST, /* DEPRECATED */
- FFM_PRESET_FASTER, /* DEPRECATED */
- FFM_PRESET_FAST, /* DEPRECATED */
- FFM_PRESET_MEDIUM, /* DEPRECATED */
- FFM_PRESET_SLOW, /* DEPRECATED */
- FFM_PRESET_SLOWER, /* DEPRECATED */
- FFM_PRESET_VERYSLOW, /* DEPRECATED */
+ FFM_PRESET_ULTRAFAST = 1, /* DEPRECATED */
+ FFM_PRESET_SUPERFAST = 2, /* DEPRECATED */
+ FFM_PRESET_VERYFAST = 3, /* DEPRECATED */
+ FFM_PRESET_FASTER = 4, /* DEPRECATED */
+ FFM_PRESET_FAST = 5, /* DEPRECATED */
+ FFM_PRESET_MEDIUM = 6, /* DEPRECATED */
+ FFM_PRESET_SLOW = 7, /* DEPRECATED */
+ FFM_PRESET_SLOWER = 8, /* DEPRECATED */
+ FFM_PRESET_VERYSLOW = 9, /* DEPRECATED */
#endif
/* Used by WEBM/VP9 and h.264 to control encoding speed vs. file size.
@@ -121,9 +121,9 @@ typedef enum eFFMpegPreset {
/** the default and recommended for most applications */
FFM_PRESET_GOOD = 10,
/** recommended if you have lots of time and want the best compression efficiency */
- FFM_PRESET_BEST,
+ FFM_PRESET_BEST = 11,
/** recommended for live / fast encoding */
- FFM_PRESET_REALTIME,
+ FFM_PRESET_REALTIME = 12,
} eFFMpegPreset;
/* Mapping from easily-understandable descriptions to CRF values.
@@ -2194,14 +2194,14 @@ typedef enum eSculptFlags {
/* ImagePaintSettings.mode */
typedef enum eImagePaintMode {
- IMAGEPAINT_MODE_MATERIAL, /* detect texture paint slots from the material */
- IMAGEPAINT_MODE_IMAGE, /* select texture paint image directly */
+ IMAGEPAINT_MODE_MATERIAL = 0, /* detect texture paint slots from the material */
+ IMAGEPAINT_MODE_IMAGE = 1, /* select texture paint image directly */
} eImagePaintMode;
/* ImagePaintSettings.interp */
enum {
IMAGEPAINT_INTERP_LINEAR = 0,
- IMAGEPAINT_INTERP_CLOSEST,
+ IMAGEPAINT_INTERP_CLOSEST = 1,
};
/* ImagePaintSettings.flag */
@@ -2301,17 +2301,17 @@ typedef enum eGPencil_Selectmode_types {
/* ToolSettings.gpencil_guide_types */
typedef enum eGPencil_GuideTypes {
GP_GUIDE_CIRCULAR = 0,
- GP_GUIDE_RADIAL,
- GP_GUIDE_PARALLEL,
- GP_GUIDE_GRID,
- GP_GUIDE_ISO,
+ GP_GUIDE_RADIAL = 1,
+ GP_GUIDE_PARALLEL = 2,
+ GP_GUIDE_GRID = 3,
+ GP_GUIDE_ISO = 4,
} eGPencil_GuideTypes;
/* ToolSettings.gpencil_guide_references */
typedef enum eGPencil_Guide_Reference {
GP_GUIDE_REF_CURSOR = 0,
- GP_GUIDE_REF_CUSTOM,
- GP_GUIDE_REF_OBJECT,
+ GP_GUIDE_REF_CUSTOM = 1,
+ GP_GUIDE_REF_OBJECT = 2,
} eGPencil_Guide_Reference;
/* ToolSettings.particle flag */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 9a59b69604d..8497d363179 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -306,8 +306,8 @@ enum GlobalAreaFlag {
};
typedef enum GlobalAreaAlign {
- GLOBAL_AREA_ALIGN_TOP,
- GLOBAL_AREA_ALIGN_BOTTOM,
+ GLOBAL_AREA_ALIGN_TOP = 0,
+ GLOBAL_AREA_ALIGN_BOTTOM = 1,
} GlobalAreaAlign;
typedef struct ScrArea_Runtime {
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 17b3528aadf..9fee839f979 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -468,6 +468,7 @@ typedef struct SequencerScopes {
#define SEQ_SPEED_INTEGRATE (1 << 0)
#define SEQ_SPEED_UNUSED_1 (1 << 1) /* cleared */
#define SEQ_SPEED_COMPRESS_IPO_Y (1 << 2)
+#define SEQ_SPEED_USE_INTERPOLATION (1 << 3)
/* ***************** SEQUENCE ****************** */
#define SEQ_NAME_MAXSTR 64
@@ -634,7 +635,7 @@ enum {
seqModifierType_Mask = 5,
seqModifierType_WhiteBalance = 6,
seqModifierType_Tonemap = 7,
-
+ /* Keep last. */
NUM_SEQUENCE_MODIFIER_TYPES,
};
diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h
index e0931d8cac3..18a4e8655a3 100644
--- a/source/blender/makesdna/DNA_shader_fx_types.h
+++ b/source/blender/makesdna/DNA_shader_fx_types.h
@@ -42,6 +42,7 @@ typedef enum ShaderFxType {
eShaderFxType_Colorize = 8,
eShaderFxType_Shadow = 9,
eShaderFxType_Glow = 10,
+ /* Keep last. */
NUM_SHADER_FX_TYPES,
} ShaderFxType;
diff --git a/source/blender/makesdna/DNA_simulation_defaults.h b/source/blender/makesdna/DNA_simulation_defaults.h
new file mode 100644
index 00000000000..b4cecd861a9
--- /dev/null
+++ b/source/blender/makesdna/DNA_simulation_defaults.h
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_SIMULATION_DEFAULTS_H__
+#define __DNA_SIMULATION_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Simulation Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Simulation \
+ { \
+ .flag = 0, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_SIMULATION_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h
new file mode 100644
index 00000000000..113c301bb9e
--- /dev/null
+++ b/source/blender/makesdna/DNA_simulation_types.h
@@ -0,0 +1,41 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_SIMULATION_TYPES_H__
+#define __DNA_SIMULATION_TYPES_H__
+
+#include "DNA_ID.h"
+
+typedef struct Simulation {
+ ID id;
+ struct AnimData *adt; /* animation data (must be immediately after id) */
+
+ struct bNodeTree *nodetree;
+
+ int flag;
+ int _pad1[1];
+} Simulation;
+
+/* Simulation.flag */
+enum {
+ SIM_DS_EXPAND = (1 << 0),
+};
+
+#endif /* __DNA_SIMULATION_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 648d35c9a2d..c1bfbe8a8b2 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -212,7 +212,7 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_SHADERFX = 15,
BCONTEXT_OUTPUT = 16,
- /* always as last... */
+ /* Keep last. */
BCONTEXT_TOT,
} eSpaceButtons_Context;
@@ -1075,7 +1075,9 @@ typedef struct SpaceImage {
int flag;
char pixel_snap_mode;
- char _pad2[3];
+ char _pad2[7];
+
+ float uv_opacity;
int tile_grid_shape[2];
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index ab9f3d07849..32a00cc25d1 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -70,6 +70,9 @@ typedef struct MovieTrackingCamera {
/* Division distortion model coefficients */
float division_k1, division_k2;
+
+ /* Nuke distortion model coefficients */
+ float nuke_k1, nuke_k2;
} MovieTrackingCamera;
typedef struct MovieTrackingMarker {
@@ -455,6 +458,7 @@ typedef struct MovieTracking {
enum {
TRACKING_DISTORTION_MODEL_POLYNOMIAL = 0,
TRACKING_DISTORTION_MODEL_DIVISION = 1,
+ TRACKING_DISTORTION_MODEL_NUKE = 2,
};
/* MovieTrackingCamera->units */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 7a09059e344..d40f07c1fff 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -619,9 +619,8 @@ typedef struct UserDef_FileSpaceData {
typedef struct UserDef_Experimental {
char use_undo_legacy;
- char use_menu_search;
/** `makesdna` does not allow empty structs. */
- char _pad0[6];
+ char _pad0[7];
} UserDef_Experimental;
#define USER_EXPERIMENTAL_TEST(userdef, member) \
@@ -1290,8 +1289,8 @@ typedef enum eUserpref_RenderDisplayType {
} eUserpref_RenderDisplayType;
typedef enum eUserpref_TempSpaceDisplayType {
- USER_TEMP_SPACE_DISPLAY_FULLSCREEN,
- USER_TEMP_SPACE_DISPLAY_WINDOW,
+ USER_TEMP_SPACE_DISPLAY_FULLSCREEN = 0,
+ USER_TEMP_SPACE_DISPLAY_WINDOW = 1,
} eUserpref_TempSpaceDisplayType;
typedef enum eUserpref_EmulateMMBMod {
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 21def800e4a..e486730ebcf 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -489,6 +489,7 @@ enum {
V3D_OVERLAY_HIDE_BONES = (1 << 8),
V3D_OVERLAY_HIDE_OBJECT_XTRAS = (1 << 9),
V3D_OVERLAY_HIDE_OBJECT_ORIGINS = (1 << 10),
+ V3D_OVERLAY_STATS = (1 << 11),
};
/** #View3DOverlay.edit_flag */
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index 1a49df86761..b3615e87a50 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -95,9 +95,9 @@ enum {
/* Volume.sequence_mode */
typedef enum VolumeSequenceMode {
VOLUME_SEQUENCE_CLIP = 0,
- VOLUME_SEQUENCE_EXTEND,
- VOLUME_SEQUENCE_REPEAT,
- VOLUME_SEQUENCE_PING_PONG,
+ VOLUME_SEQUENCE_EXTEND = 1,
+ VOLUME_SEQUENCE_REPEAT = 2,
+ VOLUME_SEQUENCE_PING_PONG = 3,
} VolumeSequenceMode;
/* VolumeDisplay.wireframe_type */
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index a101e96e958..1b0bf086269 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -146,6 +146,7 @@ set(SRC
../DNA_object_defaults.h
../DNA_pointcloud_defaults.h
../DNA_scene_defaults.h
+ ../DNA_simulation_defaults.h
../DNA_speaker_defaults.h
../DNA_texture_defaults.h
../DNA_vec_defaults.h
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index dadd2fd9d7d..2d86e97debf 100644
--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -71,6 +71,7 @@
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
@@ -93,6 +94,7 @@
#include "DNA_object_defaults.h"
#include "DNA_pointcloud_defaults.h"
#include "DNA_scene_defaults.h"
+#include "DNA_simulation_defaults.h"
#include "DNA_speaker_defaults.h"
#include "DNA_texture_defaults.h"
#include "DNA_volume_defaults.h"
@@ -150,6 +152,9 @@ SDNA_DEFAULT_DECL_STRUCT(PointCloud);
SDNA_DEFAULT_DECL_STRUCT(Scene);
SDNA_DEFAULT_DECL_STRUCT(ToolSettings);
+/* DNA_simulation_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Simulation);
+
/* DNA_speaker_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(Speaker);
@@ -260,6 +265,9 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL_EX(GP_Sculpt_Settings, ToolSettings.gp_sculpt),
SDNA_DEFAULT_DECL_EX(GP_Sculpt_Guide, ToolSettings.gp_sculpt.guide),
+ /* DNA_simulation_defaults.h */
+ SDNA_DEFAULT_DECL(Simulation),
+
/* DNA_speaker_defaults.h */
SDNA_DEFAULT_DECL(Speaker),
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 39b26fef176..49f778f2eb1 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -136,6 +136,7 @@ static const char *includefiles[] = {
"DNA_hair_types.h",
"DNA_pointcloud_types.h",
"DNA_volume_types.h",
+ "DNA_simulation_types.h",
/* see comment above before editing! */
@@ -1590,6 +1591,7 @@ int main(int argc, char **argv)
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 31d1ed54fa1..d2e27bdbcad 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -259,6 +259,7 @@ extern StructRNA RNA_FreestyleLineStyle;
extern StructRNA RNA_FreestyleModuleSettings;
extern StructRNA RNA_FreestyleSettings;
extern StructRNA RNA_Function;
+extern StructRNA RNA_FunctionNode;
extern StructRNA RNA_GPencilFrame;
extern StructRNA RNA_GPencilInterpolateSettings;
extern StructRNA RNA_GPencilLayer;
@@ -548,6 +549,9 @@ extern StructRNA RNA_ShrinkwrapConstraint;
extern StructRNA RNA_ShrinkwrapModifier;
extern StructRNA RNA_SimpleDeformModifier;
extern StructRNA RNA_SimplifyGpencilModifier;
+extern StructRNA RNA_Simulation;
+extern StructRNA RNA_SimulationNode;
+extern StructRNA RNA_SimulationNodeTree;
extern StructRNA RNA_SkinModifier;
extern StructRNA RNA_SmoothGpencilModifier;
extern StructRNA RNA_SmoothModifier;
@@ -930,10 +934,6 @@ void RNA_property_update_main(struct Main *bmain,
PropertyRNA *prop);
bool RNA_property_update_check(struct PropertyRNA *prop);
-void RNA_property_update_cache_add(PointerRNA *ptr, PropertyRNA *prop);
-void RNA_property_update_cache_flush(struct Main *bmain, struct Scene *scene);
-void RNA_property_update_cache_free(void);
-
/* Property Data */
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index fef98f9da4b..b6bae805636 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -23,6 +23,10 @@
#include "RNA_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bNodeSocketType;
struct bNodeTreeType;
struct bNodeType;
@@ -191,6 +195,8 @@ extern const EnumPropertyItem rna_enum_node_socket_in_out_items[];
extern const EnumPropertyItem rna_enum_node_math_items[];
extern const EnumPropertyItem rna_enum_mapping_type_items[];
extern const EnumPropertyItem rna_enum_node_vec_math_items[];
+extern const EnumPropertyItem rna_enum_node_boolean_math_items[];
+extern const EnumPropertyItem rna_enum_node_float_compare_items[];
extern const EnumPropertyItem rna_enum_node_filter_items[];
extern const EnumPropertyItem rna_enum_node_map_range_items[];
extern const EnumPropertyItem rna_enum_node_clamp_items[];
@@ -315,4 +321,8 @@ const EnumPropertyItem *RNA_mask_local_itemf(struct bContext *C,
/* Non confirming, utility function. */
const EnumPropertyItem *RNA_enum_node_tree_types_itemf_impl(struct bContext *C, bool *r_free);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __RNA_ENUM_TYPES_H__ */
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 64b7a3e70c1..cd05aba8794 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -103,6 +103,13 @@ if(WITH_NEW_OBJECT_TYPES)
)
endif()
+if (WITH_NEW_SIMULATION_TYPE)
+ list(APPEND DEFSRC
+ rna_simulation.c
+ )
+endif()
+
+
set(APISRC
rna_action_api.c
rna_animation_api.c
@@ -342,6 +349,11 @@ if(WITH_NEW_OBJECT_TYPES)
add_definitions(-DWITH_NEW_OBJECT_TYPES)
endif()
+if (WITH_NEW_SIMULATION_TYPE)
+ add_definitions(-DWITH_NEW_SIMULATION_TYPE)
+endif()
+
+
# Build makesrna executable
blender_include_dirs(
.
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 46854bc6307..86a088f38ed 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -4302,6 +4302,9 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_screen.c", NULL, RNA_def_screen},
{"rna_sculpt_paint.c", NULL, RNA_def_sculpt_paint},
{"rna_sequencer.c", "rna_sequencer_api.c", RNA_def_sequencer},
+#ifdef WITH_NEW_SIMULATION_TYPE
+ {"rna_simulation.c", NULL, RNA_def_simulation},
+#endif
{"rna_space.c", "rna_space_api.c", RNA_def_space},
{"rna_speaker.c", NULL, RNA_def_speaker},
{"rna_test.c", NULL, RNA_def_test},
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 699ce0f041e..891c30af466 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -71,6 +71,9 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
{ID_PA, "PARTICLE", ICON_PARTICLE_DATA, "Particle", ""},
{ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""},
{ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""},
+#ifdef WITH_NEW_SIMULATION_TYPE
+ {ID_SIM, "SIMULATION", ICON_PHYSICS, "Simulation", ""}, /* TODO: Use correct icon. */
+#endif
{ID_SO, "SOUND", ICON_SOUND, "Sound", ""},
{ID_SPK, "SPEAKER", ICON_SPEAKER, "Speaker", ""},
{ID_TXT, "TEXT", ICON_TEXT, "Text", ""},
@@ -303,6 +306,11 @@ short RNA_type_to_ID_code(const StructRNA *type)
if (base_type == &RNA_Screen) {
return ID_SCR;
}
+# ifdef WITH_NEW_SIMULATION_TYPE
+ if (base_type == &RNA_Simulation) {
+ return ID_SIM;
+ }
+# endif
if (base_type == &RNA_Sound) {
return ID_SO;
}
@@ -405,6 +413,12 @@ StructRNA *ID_code_to_RNA_type(short idcode)
return &RNA_Scene;
case ID_SCR:
return &RNA_Screen;
+ case ID_SIM:
+# ifdef WITH_NEW_SIMULATION_TYPE
+ return &RNA_Simulation;
+# else
+ return &RNA_ID;
+# endif
case ID_SO:
return &RNA_Sound;
case ID_SPK:
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index b56a18c18a9..85892758a88 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -98,8 +98,6 @@ void RNA_exit(void)
{
StructRNA *srna;
- RNA_property_update_cache_free();
-
for (srna = BLENDER_RNA.structs.first; srna; srna = srna->cont.next) {
if (srna->cont.prophash) {
BLI_ghash_free(srna->cont.prophash, NULL, NULL);
@@ -2308,115 +2306,6 @@ void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, Proper
rna_property_update(NULL, bmain, scene, ptr, prop);
}
-/* RNA Updates Cache ------------------------ */
-/* Overview of RNA Update cache system:
- *
- * RNA Update calls need to be cached in order to maintain reasonable performance
- * of the animation system (i.e. maintaining a somewhat interactive framerate)
- * while still allowing updates to be called (necessary in particular for modifier
- * property updates to actually work).
- *
- * The cache is structured with a dual-layer structure
- * - L1 = PointerRNA used as key; owner_id is used (it should always be defined,
- * and most updates end up using just that anyways)
- * - L2 = Update functions to be called on those PointerRNA's
- */
-
-/* cache element */
-typedef struct tRnaUpdateCacheElem {
- struct tRnaUpdateCacheElem *next, *prev;
-
- PointerRNA ptr; /* L1 key - id as primary, data secondary/ignored? */
- ListBase L2Funcs; /* L2 functions (LinkData<RnaUpdateFuncRef>) */
-} tRnaUpdateCacheElem;
-
-/* cache global (tRnaUpdateCacheElem's) - only accessible using these API calls */
-static ListBase rna_updates_cache = {NULL, NULL};
-
-/* ........................... */
-
-void RNA_property_update_cache_add(PointerRNA *ptr, PropertyRNA *prop)
-{
- const bool is_rna = (prop->magic == RNA_MAGIC);
- tRnaUpdateCacheElem *uce = NULL;
- UpdateFunc fn = NULL;
- LinkData *ld;
-
- /* sanity check */
- if (NULL == ptr) {
- return;
- }
-
- prop = rna_ensure_property(prop);
-
- /* we can only handle update calls with no context args for now (makes animsys updates easier) */
- if ((is_rna == false) || (prop->update == NULL) || (prop->flag & PROP_CONTEXT_UPDATE)) {
- return;
- }
- fn = prop->update;
-
- /* find cache element for which key matches... */
- for (uce = rna_updates_cache.first; uce; uce = uce->next) {
- /* Just match by id only for now,
- * since most update calls that we'll encounter only really care about this. */
- /* TODO: later, the cache might need to have some nesting on L1 to cope better
- * with these problems + some tagging to indicate we need this */
- if (uce->ptr.owner_id == ptr->owner_id) {
- break;
- }
- }
- if (uce == NULL) {
- /* create new instance */
- uce = MEM_callocN(sizeof(tRnaUpdateCacheElem), "tRnaUpdateCacheElem");
- BLI_addtail(&rna_updates_cache, uce);
-
- /* copy pointer */
- RNA_pointer_create(ptr->owner_id, ptr->type, ptr->data, &uce->ptr);
- }
-
- /* check on the update func */
- for (ld = uce->L2Funcs.first; ld; ld = ld->next) {
- /* stop on match - function already cached */
- if (fn == ld->data) {
- return;
- }
- }
- /* else... if still here, we need to add it */
- BLI_addtail(&uce->L2Funcs, BLI_genericNodeN(fn));
-}
-
-void RNA_property_update_cache_flush(Main *bmain, Scene *scene)
-{
- tRnaUpdateCacheElem *uce;
-
- /* TODO: should we check that bmain and scene are valid? The above stuff doesn't! */
-
- /* execute the cached updates */
- for (uce = rna_updates_cache.first; uce; uce = uce->next) {
- LinkData *ld;
-
- for (ld = uce->L2Funcs.first; ld; ld = ld->next) {
- UpdateFunc fn = (UpdateFunc)ld->data;
- fn(bmain, scene, &uce->ptr);
- }
- }
-}
-
-void RNA_property_update_cache_free(void)
-{
- tRnaUpdateCacheElem *uce, *ucn;
-
- for (uce = rna_updates_cache.first; uce; uce = ucn) {
- ucn = uce->next;
-
- /* free L2 cache */
- BLI_freelistN(&uce->L2Funcs);
-
- /* remove self */
- BLI_freelinkN(&rna_updates_cache, uce);
- }
-}
-
/* ---------------------------------------------------------------------- */
/* Property Data */
@@ -5785,10 +5674,10 @@ static char *rna_idp_path(PointerRNA *ptr,
}
/**
- * Find the path from the structure referenced by the pointer to the IDProperty object.
+ * Find the path from the structure referenced by the pointer to the #IDProperty object.
*
- * \param ptr Reference to the object owning the custom property storage.
- * \param needle Custom property object to find.
+ * \param ptr: Reference to the object owning the custom property storage.
+ * \param needle: Custom property object to find.
* \return Relative path or NULL.
*/
char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle)
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 33f19153e3a..ea8b0cd758b 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -213,6 +213,7 @@ static StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr)
# include "BKE_anim_data.h"
# include "BKE_fcurve.h"
+# include "BKE_fcurve_driver.h"
# include "DEG_depsgraph.h"
# include "DEG_depsgraph_build.h"
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index 0a6554a1cea..86860e5e14b 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -2467,7 +2467,7 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Random", "Amount of random velocity");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
- prop = RNA_def_property(srna, "velocity_coord", PROP_FLOAT, PROP_XYZ);
+ prop = RNA_def_property(srna, "velocity_coord", PROP_FLOAT, PROP_VELOCITY);
RNA_def_property_float_sdna(prop, NULL, "vel_coord");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, -1000.1, 1000.1);
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index f09d25ece41..b36cc493447 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -1664,13 +1664,11 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mask_layer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_MASK);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Mask Layer", "Mask pixels from underlying layers drawing");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "use_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_LIGHTS);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
prop, "Use Lights", "Enable the use of lights on stroke and fill materials");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 5475f62cb8c..1906c663c54 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -129,6 +129,11 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
"Opacity",
"Opacity of the strokes"},
{eGpencilModifierType_Tint, "GP_TINT", ICON_MOD_TINT, "Tint", "Tint strokes with new color"},
+ {eGpencilModifierType_Texture,
+ "GP_TEXTURE",
+ ICON_TEXTURE,
+ "Texture Mapping",
+ "Change stroke uv texture values"},
{0, NULL, 0, NULL, NULL},
};
@@ -234,6 +239,8 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
return &RNA_ArmatureGpencilModifier;
case eGpencilModifierType_Multiply:
return &RNA_MultiplyGpencilModifier;
+ case eGpencilModifierType_Texture:
+ return &RNA_TextureGpencilModifier;
/* Default */
case eGpencilModifierType_None:
case NUM_GREASEPENCIL_MODIFIER_TYPES:
@@ -302,6 +309,7 @@ RNA_GP_MOD_VGROUP_NAME_SET(Smooth, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Hook, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Offset, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Armature, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Texture, vgname);
# undef RNA_GP_MOD_VGROUP_NAME_SET
@@ -2138,6 +2146,141 @@ static void rna_def_modifier_gpencilmultiply(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
+static void rna_def_modifier_gpenciltexture(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem fit_type_items[] = {
+ {GP_TEX_CONSTANT_LENGTH,
+ "CONSTANT_LENGTH",
+ 0,
+ "Keep Texture at Constant Length",
+ "Keep the texture at a constant length regardless of the length of each stroke"},
+ {GP_TEX_FIT_STROKE,
+ "FIT_STROKE",
+ 0,
+ "Fit Texture to Stroke Length",
+ "Scale the texture to fit the length of each stroke"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem mode_items[] = {
+ {STROKE, "STROKE", 0, "Stroke", "Manipulate only stroke texture coordinates"},
+ {FILL, "FILL", 0, "Fill", "Manipulate only fill texture coordinates"},
+ {STROKE_AND_FILL,
+ "STROKE_AND_FILL",
+ 0,
+ "Stroke and Fill",
+ "Manipulate both stroke and fill texture coordinates"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "TextureGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(
+ srna, "Texture Modifier", "Transform stroke texture coordinates Modifier");
+ RNA_def_struct_sdna(srna, "TextureGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_TEXTURE);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TEX_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "materialname");
+ RNA_def_property_ui_text(prop, "Material", "Material name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_materials", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TEX_INVERT_MATERIAL);
+ RNA_def_property_ui_text(prop, "Inverse Materials", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_TextureGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TEX_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TEX_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TEX_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "uv_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -100.0, 100.0, 0.1, 3);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop, "Offset UVs", "Offset value to add to stroke UVs");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "uv_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "uv_scale");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "UV Scale", "Factor to scale the UVs");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "fill_rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "fill_rotation");
+ RNA_def_property_ui_text(prop, "Fill Rotation", "Additional rotation of the fill UV");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "fill_offset", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "fill_offset");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Fill Offset", "Additional offset of the fill UV");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "fill_scale", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "fill_scale");
+ RNA_def_property_range(prop, 0.01f, 100.0f);
+ RNA_def_property_ui_text(prop, "Fill Scale", "Additional scale of the fill UV");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "fit_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "fit_method");
+ RNA_def_property_enum_items(prop, fit_type_items);
+ RNA_def_property_ui_text(prop, "Fit Method", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+}
+
void RNA_def_greasepencil_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2211,6 +2354,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
rna_def_modifier_gpencilhook(brna);
rna_def_modifier_gpencilarmature(brna);
rna_def_modifier_gpencilmultiply(brna);
+ rna_def_modifier_gpenciltexture(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 27097261930..cb59eee6afa 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -185,6 +185,7 @@ void RNA_def_render(struct BlenderRNA *brna);
void RNA_def_rigidbody(struct BlenderRNA *brna);
void RNA_def_rna(struct BlenderRNA *brna);
void RNA_def_scene(struct BlenderRNA *brna);
+void RNA_def_simulation(struct BlenderRNA *brna);
void RNA_def_view_layer(struct BlenderRNA *brna);
void RNA_def_screen(struct BlenderRNA *brna);
void RNA_def_sculpt_paint(struct BlenderRNA *brna);
@@ -449,6 +450,7 @@ void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_hairs(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_simulations(BlenderRNA *brna, PropertyRNA *cprop);
/* ID Properties */
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 855d5f46890..2f37e4079c7 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -134,6 +134,9 @@ RNA_MAIN_LISTBASE_FUNCS_DEF(pointclouds)
RNA_MAIN_LISTBASE_FUNCS_DEF(scenes)
RNA_MAIN_LISTBASE_FUNCS_DEF(screens)
RNA_MAIN_LISTBASE_FUNCS_DEF(shapekeys)
+# ifdef WITH_NEW_SIMULATION_TYPE
+RNA_MAIN_LISTBASE_FUNCS_DEF(simulations)
+# endif
RNA_MAIN_LISTBASE_FUNCS_DEF(sounds)
RNA_MAIN_LISTBASE_FUNCS_DEF(speakers)
RNA_MAIN_LISTBASE_FUNCS_DEF(texts)
@@ -402,6 +405,14 @@ void RNA_def_main(BlenderRNA *brna)
"Volumes",
"Volume data-blocks",
RNA_def_main_volumes},
+# ifdef WITH_NEW_SIMULATION_TYPE
+ {"simulations",
+ "Simulation",
+ "rna_Main_simulations_begin",
+ "Simulations",
+ "Simulation data-blocks",
+ RNA_def_main_simulations},
+# endif
{NULL, NULL, NULL, NULL, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 9799054ccd2..c5781175d65 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -69,6 +69,7 @@
# include "BKE_particle.h"
# include "BKE_pointcloud.h"
# include "BKE_scene.h"
+# include "BKE_simulation.h"
# include "BKE_sound.h"
# include "BKE_speaker.h"
# include "BKE_text.h"
@@ -98,6 +99,7 @@
# include "DNA_node_types.h"
# include "DNA_particle_types.h"
# include "DNA_pointcloud_types.h"
+# include "DNA_simulation_types.h"
# include "DNA_sound_types.h"
# include "DNA_speaker_types.h"
# include "DNA_text_types.h"
@@ -738,6 +740,18 @@ static Volume *rna_Main_volumes_new(Main *bmain, const char *name)
return volume;
}
+# ifdef WITH_NEW_SIMULATION_TYPE
+static Simulation *rna_Main_simulations_new(Main *bmain, const char *name)
+{
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Simulation *simulation = BKE_simulation_add(bmain, safe_name);
+ id_us_min(&simulation->id);
+ return simulation;
+}
+# endif
+
/* tag functions, all the same */
# define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \
static void rna_Main_##_func_name##_tag(Main *bmain, bool value) \
@@ -785,6 +799,9 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(hairs, hairs, ID_HA)
RNA_MAIN_ID_TAG_FUNCS_DEF(pointclouds, pointclouds, ID_PT)
# endif
RNA_MAIN_ID_TAG_FUNCS_DEF(volumes, volumes, ID_VO)
+# ifdef WITH_NEW_SIMULATION_TYPE
+RNA_MAIN_ID_TAG_FUNCS_DEF(simulations, simulations, ID_SIM)
+# endif
# undef RNA_MAIN_ID_TAG_FUNCS_DEF
@@ -2304,4 +2321,44 @@ void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
+void RNA_def_main_simulations(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "BlendDataSimulations");
+ srna = RNA_def_struct(brna, "BlendDataSimulations", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Simulations", "Collection of simulations");
+
+ func = RNA_def_function(srna, "new", "rna_Main_simulations_new");
+ RNA_def_function_ui_description(func, "Add a new simulation to the main database");
+ parm = RNA_def_string(func, "name", "Simulation", 0, "", "New name for the data-block");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "simulation", "Simulation", "", "New simulation data-block");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove a simulation from the current blendfile");
+ parm = RNA_def_pointer(func, "simulation", "Simulation", "", "Simulation to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_boolean(
+ func, "do_unlink", true, "", "Unlink all usages of this simulation before deleting it");
+ RNA_def_boolean(func,
+ "do_id_user",
+ true,
+ "",
+ "Decrement user counter of all datablocks used by this simulation data");
+ RNA_def_boolean(
+ func, "do_ui_user", true, "", "Make sure interface does not reference this simulation data");
+
+ func = RNA_def_function(srna, "tag", "rna_Main_simulations_tag");
+ parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+}
+
#endif
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index e13b9caa90c..645527bce22 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -266,7 +266,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_WAVE,
"Wave",
"Adds a ripple-like motion to an object’s geometry"},
- {0, "", 0, N_("Simulate"), ""},
+ {0, "", 0, N_("Physics"), ""},
{eModifierType_Cloth, "CLOTH", ICON_MOD_CLOTH, "Cloth", ""},
{eModifierType_Collision, "COLLISION", ICON_MOD_PHYSICS, "Collision", ""},
{eModifierType_DynamicPaint, "DYNAMIC_PAINT", ICON_MOD_DYNAMICPAINT, "Dynamic Paint", ""},
@@ -920,7 +920,7 @@ static bool rna_HookModifier_object_override_apply(Main *UNUSED(bmain),
{
BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0);
BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_REPLACE &&
- "Unsupported RNA override operation on Hook modifier target objet pointer");
+ "Unsupported RNA override operation on Hook modifier target object pointer");
UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop);
/* We need a special handling here because setting hook target resets invert parent matrix,
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 71b3f1ee94b..8089aa389c9 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -81,6 +81,35 @@ static const EnumPropertyItem node_socket_type_items[] = {
{SOCK_STRING, "STRING", 0, "String", ""},
{SOCK_RGBA, "RGBA", 0, "RGBA", ""},
{SOCK_SHADER, "SHADER", 0, "Shader", ""},
+ {SOCK_OBJECT, "OBJECT", 0, "Object", ""},
+ {SOCK_IMAGE, "IMAGE", 0, "Image", ""},
+ {SOCK_EMITTERS, "EMITTERS", 0, "Emitters", ""},
+ {SOCK_EVENTS, "EVENTS", 0, "Events", ""},
+ {SOCK_FORCES, "FORCES", 0, "Forces", ""},
+ {SOCK_CONTROL_FLOW, "CONTROL_FLOW", 0, "Control Flow", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static const EnumPropertyItem particle_attribute_socket_type_items[] = {
+ {SOCK_FLOAT, "FLOAT", 0, "Float", ""},
+ {SOCK_INT, "INT", 0, "Int", ""},
+ {SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
+ {SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
+ {SOCK_RGBA, "RGBA", 0, "Color", ""},
+ {SOCK_OBJECT, "OBJECT", 0, "Object", ""},
+ {SOCK_IMAGE, "IMAGE", 0, "Image", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static const EnumPropertyItem node_socket_data_type_items[] = {
+ {SOCK_FLOAT, "FLOAT", 0, "Float", ""},
+ {SOCK_INT, "INT", 0, "Int", ""},
+ {SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
+ {SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
+ {SOCK_STRING, "STRING", 0, "String", ""},
+ {SOCK_RGBA, "RGBA", 0, "Color", ""},
+ {SOCK_OBJECT, "OBJECT", 0, "Object", ""},
+ {SOCK_IMAGE, "IMAGE", 0, "Image", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -244,6 +273,47 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
+ {NODE_BOOLEAN_MATH_AND, "AND", 0, "And", "Outputs true only when both inputs are true"},
+ {NODE_BOOLEAN_MATH_OR, "OR", 0, "Or", "Outputs or when at least one of the inputs is true"},
+ {NODE_BOOLEAN_MATH_NOT, "NOT", 0, "Not", "Outputs the opposite of the input"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_node_float_compare_items[] = {
+ {NODE_FLOAT_COMPARE_LESS_THAN,
+ "LESS_THAN",
+ 0,
+ "A < B",
+ "True when the first input is smaller than second input"},
+ {NODE_FLOAT_COMPARE_LESS_EQUAL,
+ "LESS_EQUAL",
+ 0,
+ "A <= B",
+ "True when the first input is smaller than the second input or equal"},
+ {NODE_FLOAT_COMPARE_GREATER_THAN,
+ "GREATER_THAN",
+ 0,
+ "A > B",
+ "True when the first input is greater than the second input"},
+ {NODE_FLOAT_COMPARE_GREATER_EQUAL,
+ "GREATER_EQUAL",
+ 0,
+ "A >= B",
+ "True when the first input is greater than the second input or equal"},
+ {NODE_FLOAT_COMPARE_EQUAL,
+ "EQUAL",
+ 0,
+ "A = B",
+ "True when both inputs are approximately equal"},
+ {NODE_FLOAT_COMPARE_NOT_EQUAL,
+ "NOT_EQUAL",
+ 0,
+ "A != B",
+ "True when both inputs are not approximately equal"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_node_map_range_items[] = {
{NODE_MAP_RANGE_LINEAR,
"LINEAR",
@@ -669,6 +739,34 @@ static const EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C),
# undef DefNode
}
+ if (RNA_struct_is_a(ptr->type, &RNA_SimulationNode)) {
+# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
+ if (STREQ(#Category, "SimulationNode")) { \
+ tmp.value = ID; \
+ tmp.identifier = EnumName; \
+ tmp.name = UIName; \
+ tmp.description = UIDesc; \
+ tmp.icon = ICON_NONE; \
+ RNA_enum_item_add(&item, &totitem, &tmp); \
+ }
+# include "../../nodes/NOD_static_types.h"
+# undef DefNode
+ }
+
+ if (RNA_struct_is_a(ptr->type, &RNA_FunctionNode)) {
+# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
+ if (STREQ(#Category, "FunctionNode")) { \
+ tmp.value = ID; \
+ tmp.identifier = EnumName; \
+ tmp.name = UIName; \
+ tmp.description = UIDesc; \
+ tmp.icon = ICON_NONE; \
+ RNA_enum_item_add(&item, &totitem, &tmp); \
+ }
+# include "../../nodes/NOD_static_types.h"
+# undef DefNode
+ }
+
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -1785,6 +1883,50 @@ static StructRNA *rna_TextureNode_register(Main *bmain,
return nt->rna_ext.srna;
}
+static StructRNA *rna_SimulationNode_register(Main *bmain,
+ ReportList *reports,
+ void *data,
+ const char *identifier,
+ StructValidateFunc validate,
+ StructCallbackFunc call,
+ StructFreeFunc free)
+{
+ bNodeType *nt = rna_Node_register_base(
+ bmain, reports, &RNA_SimulationNode, data, identifier, validate, call, free);
+ if (!nt) {
+ return NULL;
+ }
+
+ nodeRegisterType(nt);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
+
+ return nt->rna_ext.srna;
+}
+
+static StructRNA *rna_FunctionNode_register(Main *bmain,
+ ReportList *reports,
+ void *data,
+ const char *identifier,
+ StructValidateFunc validate,
+ StructCallbackFunc call,
+ StructFreeFunc free)
+{
+ bNodeType *nt = rna_Node_register_base(
+ bmain, reports, &RNA_FunctionNode, data, identifier, validate, call, free);
+ if (!nt) {
+ return NULL;
+ }
+
+ nodeRegisterType(nt);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
+
+ return nt->rna_ext.srna;
+}
+
static IDProperty *rna_Node_idprops(PointerRNA *ptr, bool create)
{
bNode *node = ptr->data;
@@ -3581,6 +3723,15 @@ static void rna_ShaderNode_socket_update(Main *bmain, Scene *scene, PointerRNA *
rna_Node_update(bmain, scene, ptr);
}
+static void rna_FunctionNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
+ bNode *node = (bNode *)ptr->data;
+
+ nodeUpdate(ntree, node);
+ rna_Node_update(bmain, scene, ptr);
+}
+
static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
@@ -3590,6 +3741,15 @@ static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA
rna_Node_update(bmain, scene, ptr);
}
+static void rna_SimulationNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
+ bNode *node = (bNode *)ptr->data;
+
+ nodeUpdate(ntree, node);
+ rna_Node_update(bmain, scene, ptr);
+}
+
static PointerRNA rna_ShaderNodePointDensity_psys_get(PointerRNA *ptr)
{
bNode *node = ptr->data;
@@ -4016,6 +4176,39 @@ static void def_math(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_boolean_math(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_node_boolean_math_items);
+ RNA_def_property_ui_text(prop, "Operation", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNode_socket_update");
+}
+
+static void def_float_compare(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items);
+ RNA_def_property_ui_text(prop, "Operation", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNode_socket_update");
+}
+
+static void def_fn_switch(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, node_socket_data_type_items);
+ RNA_def_property_ui_text(prop, "Data Type", "Data type for inputs and outputs");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNode_socket_update");
+}
+
static void def_vector_math(StructRNA *srna)
{
PropertyRNA *prop;
@@ -7899,6 +8092,82 @@ static void def_tex_bricks(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+/* -- Simulation Nodes --------------------------------------------------------- */
+
+static void def_sim_particle_time_step_event(StructRNA *srna)
+{
+ static const EnumPropertyItem mode_items[] = {
+ {NODE_PARTICLE_TIME_STEP_EVENT_BEGIN,
+ "BEGIN",
+ 0,
+ "Begin",
+ "Execute for every particle at the beginning of each time step"},
+ {NODE_PARTICLE_TIME_STEP_EVENT_END,
+ "END",
+ 0,
+ "End",
+ "Execute for every particle at the end of each time step"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "When in each time step is the event triggered");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
+static void def_sim_particle_attribute(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, particle_attribute_socket_type_items);
+ RNA_def_property_ui_text(
+ prop,
+ "Data Type",
+ "Expected type of the attribute. A default value is returned if the type is not correct");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationNode_socket_update");
+}
+
+static void def_sim_set_particle_attribute(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, particle_attribute_socket_type_items);
+ RNA_def_property_ui_text(
+ prop,
+ "Data Type",
+ "Expected type of the attribute. Nothing is done if the type is not correct");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationNode_socket_update");
+}
+
+static void def_sim_time(StructRNA *srna)
+{
+ static const EnumPropertyItem mode_items[] = {
+ {NODE_SIM_INPUT_SIMULATION_TIME,
+ "SIMULATION_TIME",
+ 0,
+ "Simulation Time",
+ "Time since start of simulation"},
+ {NODE_SIM_INPUT_SCENE_TIME, "SCENE_TIME", 0, "Scene Time", "Time shown in the timeline"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "The time to output");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationNode_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
@@ -7936,6 +8205,26 @@ static void rna_def_texture_node(BlenderRNA *brna)
RNA_def_struct_register_funcs(srna, "rna_TextureNode_register", "rna_Node_unregister", NULL);
}
+static void rna_def_simulation_node(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "SimulationNode", "NodeInternal");
+ RNA_def_struct_ui_text(srna, "Simulation Node", "");
+ RNA_def_struct_sdna(srna, "bNode");
+ RNA_def_struct_register_funcs(srna, "rna_SimulationNode_register", "rna_Node_unregister", NULL);
+}
+
+static void rna_def_function_node(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "FunctionNode", "NodeInternal");
+ RNA_def_struct_ui_text(srna, "Function Node", "");
+ RNA_def_struct_sdna(srna, "bNode");
+ RNA_def_struct_register_funcs(srna, "rna_FunctionNode_register", "rna_Node_unregister", NULL);
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_node_socket(BlenderRNA *brna)
@@ -8492,6 +8781,104 @@ static void rna_def_node_socket_virtual(BlenderRNA *brna, const char *identifier
RNA_def_struct_sdna(srna, "bNodeSocket");
}
+static void rna_def_node_socket_object(BlenderRNA *brna,
+ const char *identifier,
+ const char *interface_idname)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
+ RNA_def_struct_ui_text(srna, "Object Node Socket", "Object socket of a node");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ RNA_def_struct_sdna_from(srna, "bNodeSocketValueObject", "default_value");
+
+ prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "value");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE);
+
+ /* socket interface */
+ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
+ RNA_def_struct_ui_text(srna, "Object Node Socket Interface", "Object socket of a node");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ RNA_def_struct_sdna_from(srna, "bNodeSocketValueObject", "default_value");
+
+ prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "value");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
+}
+
+static void rna_def_node_socket_image(BlenderRNA *brna,
+ const char *identifier,
+ const char *interface_idname)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
+ RNA_def_struct_ui_text(srna, "Image Node Socket", "Image socket of a node");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ RNA_def_struct_sdna_from(srna, "bNodeSocketValueImage", "default_value");
+
+ prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "value");
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE);
+
+ /* socket interface */
+ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
+ RNA_def_struct_ui_text(srna, "Image Node Socket Interface", "Image socket of a node");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ RNA_def_struct_sdna_from(srna, "bNodeSocketValueImage", "default_value");
+
+ prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "value");
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
+}
+
+static void rna_def_node_socket_effector(BlenderRNA *brna,
+ const char *identifier,
+ const char *interface_idname)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
+ RNA_def_struct_ui_text(srna, "", "");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
+ RNA_def_struct_ui_text(srna, "", "");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+}
+
+static void rna_def_node_socket_control_flow(BlenderRNA *brna,
+ const char *identifier,
+ const char *interface_idname)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
+ RNA_def_struct_ui_text(srna, "", "");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
+ RNA_def_struct_ui_text(srna, "", "");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+}
+
static void rna_def_node_socket_standard_types(BlenderRNA *brna)
{
/* XXX Workaround: Registered functions are not exposed in python by bpy,
@@ -8626,6 +9013,17 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
rna_def_node_socket_shader(brna, "NodeSocketShader", "NodeSocketInterfaceShader");
rna_def_node_socket_virtual(brna, "NodeSocketVirtual");
+
+ rna_def_node_socket_object(brna, "NodeSocketObject", "NodeSocketInterfaceObject");
+
+ rna_def_node_socket_image(brna, "NodeSocketImage", "NodeSocketInterfaceImage");
+
+ rna_def_node_socket_effector(brna, "NodeSocketEmitters", "NodeSocketInterfaceEmitters");
+ rna_def_node_socket_effector(brna, "NodeSocketEvents", "NodeSocketInterfaceEvents");
+ rna_def_node_socket_effector(brna, "NodeSocketForces", "NodeSocketInterfaceForces");
+
+ rna_def_node_socket_control_flow(
+ brna, "NodeSocketControlFlow", "NodeSocketInterfaceControlFlow");
}
static void rna_def_internal_node(BlenderRNA *brna)
@@ -9251,6 +9649,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
{NTREE_SHADER, "SHADER", ICON_MATERIAL, "Shader", "Shader nodes"},
{NTREE_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture nodes"},
{NTREE_COMPOSIT, "COMPOSITING", ICON_RENDERLAYERS, "Compositing", "Compositing nodes"},
+ {NTREE_SIMULATION, "SIMULATION", ICON_PHYSICS, "Simulation", "Simulation nodes"},
{0, NULL, 0, NULL, NULL},
};
@@ -9474,6 +9873,17 @@ static void rna_def_texture_nodetree(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_TEXTURE);
}
+static void rna_def_simulation_nodetree(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "SimulationNodeTree", "NodeTree");
+ RNA_def_struct_ui_text(
+ srna, "Simulation Node Tree", "Node tree consisting of linked nodes used for simulations");
+ RNA_def_struct_sdna(srna, "bNodeTree");
+ RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */
+}
+
static StructRNA *define_specific_node(BlenderRNA *brna,
const char *struct_name,
const char *base_name,
@@ -9560,6 +9970,8 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_shader_node(brna);
rna_def_compositor_node(brna);
rna_def_texture_node(brna);
+ rna_def_simulation_node(brna);
+ rna_def_function_node(brna);
rna_def_nodetree(brna);
@@ -9568,6 +9980,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_composite_nodetree(brna);
rna_def_shader_nodetree(brna);
rna_def_texture_nodetree(brna);
+ rna_def_simulation_nodetree(brna);
# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
{ \
@@ -9584,12 +9997,13 @@ void RNA_def_nodetree(BlenderRNA *brna)
*/
# include "../../nodes/NOD_static_types.h"
- /* Node group types need to be defined for shader, compositor, texture nodes individually.
- * Cannot use the static types header for this, since they share the same int id.
+ /* Node group types need to be defined for shader, compositor, texture, simulation nodes
+ * individually. Cannot use the static types header for this, since they share the same int id.
*/
define_specific_node(brna, "ShaderNodeGroup", "ShaderNode", "Group", "", def_group);
define_specific_node(brna, "CompositorNodeGroup", "CompositorNode", "Group", "", def_group);
define_specific_node(brna, "TextureNodeGroup", "TextureNode", "Group", "", def_group);
+ define_specific_node(brna, "SimulationNodeGroup", "SimulationNode", "Group", "", def_group);
def_custom_group(brna,
"ShaderNodeCustomGroup",
"ShaderNode",
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 33048d4b057..c84242b2f67 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -3204,7 +3204,6 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_grease_pencil_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_USE_GPENCIL_LIGHTS);
RNA_def_property_boolean_default(prop, true);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Use Lights", "Lights affect grease pencil object");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_GPencil_update");
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index a19bbdcc369..58602cc939f 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -924,11 +924,11 @@ static void rna_Scene_volume_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_VOLUME | ID_RECALC_SEQUENCER_STRIPS);
}
-static const char *rna_Scene_statistics_string_get(Scene *scene,
- Main *bmain,
+static const char *rna_Scene_statistics_string_get(Scene *UNUSED(scene),
+ Main *UNUSED(bmain),
ViewLayer *view_layer)
{
- return ED_info_stats_string(bmain, scene, view_layer);
+ return ED_info_footer_string(view_layer);
}
static void rna_Scene_framelen_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
@@ -5718,6 +5718,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem meta_input_items[] = {
+ {0, "SCENE", 0, "Scene", "Use metadata from the current scene"},
+ {R_STAMP_STRIPMETA,
+ "STRIPS",
+ 0,
+ "Sequencer Strips",
+ "Use metadata from the strips in the sequencer"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
rna_def_scene_ffmpeg_settings(brna);
srna = RNA_def_struct(brna, "RenderSettings", NULL);
@@ -6235,10 +6245,10 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop, "Stamp Labels", "Display stamp labels (\"Camera\" in front of camera name, etc.)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "use_stamp_strip_meta", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_STRIPMETA);
- RNA_def_property_ui_text(
- prop, "Strip Metadata", "Use metadata from the strips in the sequencer");
+ prop = RNA_def_property(srna, "metadata_input", PROP_ENUM, PROP_NONE); /* as an enum */
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "stamp");
+ RNA_def_property_enum_items(prop, meta_input_items);
+ RNA_def_property_ui_text(prop, "Metadata Input", "Where to take the metadata from");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_stamp_memory", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index d218084fc66..fd8ddfff14f 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -2020,9 +2020,10 @@ static void rna_def_editor(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_prefetch", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_PREFETCH_ENABLE);
- RNA_def_property_ui_text(prop,
- "Prefetch frames",
- "Render frames ahead of playhead in background for faster playback");
+ RNA_def_property_ui_text(
+ prop,
+ "Prefetch Frames",
+ "Render frames ahead of playhead in the background for faster playback");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
prop = RNA_def_property(srna, "recycle_max_cost", PROP_FLOAT, PROP_NONE);
@@ -2760,6 +2761,13 @@ static void rna_def_speed_control(StructRNA *srna)
prop, "Scale to Length", "Scale values from 0.0 to 1.0 to target sequence length");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
+
+ prop = RNA_def_property(srna, "frame_interpolation_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_USE_INTERPOLATION);
+ RNA_def_property_ui_text(
+ prop, "Frame interpolation", "Do crossfade blending between current and next frame");
+ RNA_def_property_update(
+ prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
}
static void rna_def_gaussian_blur(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_simulation.c b/source/blender/makesrna/intern/rna_simulation.c
new file mode 100644
index 00000000000..789ea299feb
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_simulation.c
@@ -0,0 +1,56 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "DNA_simulation_types.h"
+
+#include "rna_internal.h"
+
+#ifdef RNA_RUNTIME
+
+#else
+
+static void rna_def_simulation(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "Simulation", "ID");
+ RNA_def_struct_ui_text(srna, "Simulation", "Simulation data-block");
+ RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */
+
+ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "nodetree");
+ RNA_def_property_ui_text(prop, "Node Tree", "Node tree defining the simulation");
+
+ /* common */
+ rna_def_animdata_common(srna);
+}
+
+void RNA_def_simulation(BlenderRNA *brna)
+{
+ rna_def_simulation(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 1f072d2eb26..d0a126cd115 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -45,6 +45,7 @@
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
@@ -2166,6 +2167,40 @@ static void rna_SpaceNodeEditor_node_tree_update(const bContext *C, PointerRNA *
ED_node_tree_update(C);
}
+# ifdef WITH_NEW_SIMULATION_TYPE
+static PointerRNA rna_SpaceNodeEditor_simulation_get(PointerRNA *ptr)
+{
+ SpaceNode *snode = (SpaceNode *)ptr->data;
+ ID *id = snode->id;
+ if (id && GS(id->name) == ID_SIM) {
+ return rna_pointer_inherit_refine(ptr, &RNA_Simulation, snode->id);
+ }
+ else {
+ return PointerRNA_NULL;
+ }
+}
+
+static void rna_SpaceNodeEditor_simulation_set(PointerRNA *ptr,
+ const PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ SpaceNode *snode = (SpaceNode *)ptr->data;
+ if (!STREQ(snode->tree_idname, "SimulationNodeTree")) {
+ return;
+ }
+
+ Simulation *sim = (Simulation *)value.data;
+ if (sim != NULL) {
+ bNodeTree *ntree = sim->nodetree;
+ ED_node_tree_start(snode, ntree, NULL, NULL);
+ }
+ else {
+ ED_node_tree_start(snode, NULL, NULL, NULL);
+ }
+ snode->id = &sim->id;
+}
+# endif
+
static int rna_SpaceNodeEditor_tree_type_get(PointerRNA *ptr)
{
SpaceNode *snode = (SpaceNode *)ptr->data;
@@ -2935,6 +2970,12 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
prop, "Tile Grid Shape", "How many tiles will be shown in the background");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ prop = RNA_def_property(srna, "uv_opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_opacity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "UV Opacity", "Opacity of UV overlays");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
/* todo: move edge and face drawing options here from G.f */
prop = RNA_def_property(srna, "pixel_snap_mode", PROP_ENUM, PROP_NONE);
@@ -3563,6 +3604,11 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Text", "Display overlay text");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "show_stats", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_STATS);
+ RNA_def_property_ui_text(prop, "Show Statistics", "Display scene statistics overlay text");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
prop = RNA_def_property(srna, "show_extras", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_OBJECT_XTRAS);
@@ -5521,6 +5567,13 @@ static void rna_def_fileselect_idfilter(BlenderRNA *brna)
"Show/hide Point Cloud data-blocks"},
# endif
{FILTER_ID_SCE, "filter_scene", ICON_SCENE_DATA, "Scenes", "Show Scene data-blocks"},
+# ifdef WITH_NEW_SIMULATION_TYPE
+ {FILTER_ID_SIM,
+ "filter_simulation",
+ ICON_PHYSICS,
+ "Simulations",
+ "Show Simulation data-blocks"}, /* TODO: Use correct icon. */
+# endif
{FILTER_ID_SPK, "filter_speaker", ICON_SPEAKER, "Speakers", "Show Speaker data-blocks"},
{FILTER_ID_SO, "filter_sound", ICON_SOUND, "Sounds", "Show Sound data-blocks"},
{FILTER_ID_TE, "filter_texture", ICON_TEXTURE_DATA, "Textures", "Show Texture data-blocks"},
@@ -6202,6 +6255,19 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "ID From", "Data-block from which the edited data-block is linked");
+# ifdef WITH_NEW_SIMULATION_TYPE
+ prop = RNA_def_property(srna, "simulation", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "Simulation");
+ RNA_def_property_ui_text(prop, "Simulation", "Simulation that is being edited");
+ RNA_def_property_pointer_funcs(prop,
+ "rna_SpaceNodeEditor_simulation_get",
+ "rna_SpaceNodeEditor_simulation_set",
+ NULL,
+ NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+# endif
+
prop = RNA_def_property(srna, "path", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "treepath", NULL);
RNA_def_property_struct_type(prop, "NodeTreePath");
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 131c13c4d90..507d06482df 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -1149,6 +1149,7 @@ static void rna_def_trackingCamera(BlenderRNA *brna)
"Divisions",
"Division distortion model which "
"better represents wide-angle cameras"},
+ {TRACKING_DISTORTION_MODEL_NUKE, "NUKE", 0, "Nuke", "Nuke distortion model"},
{0, NULL, 0, NULL, NULL},
};
@@ -1252,6 +1253,19 @@ static void rna_def_trackingCamera(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "K2", "First coefficient of second order division distortion");
RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate");
+ /* Nuke distortion parameters */
+ prop = RNA_def_property(srna, "nuke_k1", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_range(prop, -10, 10, 0.1, 3);
+ RNA_def_property_ui_text(prop, "K1", "First coefficient of second order Nuke distortion");
+ RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate");
+
+ prop = RNA_def_property(srna, "nuke_k2", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_range(prop, -10, 10, 0.1, 3);
+ RNA_def_property_ui_text(prop, "K2", "Second coefficient of second order Nuke distortion");
+ RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate");
+
/* pixel aspect */
prop = RNA_def_property(srna, "pixel_aspect", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "pixel_aspect");
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index a169e81237d..2a64ffa73cd 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -693,7 +693,7 @@ void RNA_api_ui_layout(StructRNA *srna)
static float node_socket_color_default[] = {0.0f, 0.0f, 0.0f, 1.0f};
/* simple layout specifiers */
- func = RNA_def_function(srna, "row", "uiLayoutRow");
+ func = RNA_def_function(srna, "row", "uiLayoutRowWithHeading");
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
RNA_def_function_ui_description(
@@ -701,8 +701,14 @@ void RNA_api_ui_layout(StructRNA *srna)
"Sub-layout. Items placed in this sublayout are placed next to each other "
"in a row");
RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
+ RNA_def_string(func,
+ "heading",
+ NULL,
+ UI_MAX_NAME_STR,
+ "Heading",
+ "Label to insert into the layout for this row");
- func = RNA_def_function(srna, "column", "uiLayoutColumn");
+ func = RNA_def_function(srna, "column", "uiLayoutColumnWithHeading");
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
RNA_def_function_ui_description(
@@ -710,6 +716,12 @@ void RNA_api_ui_layout(StructRNA *srna)
"Sub-layout. Items placed in this sublayout are placed under each other "
"in a column");
RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
+ RNA_def_string(func,
+ "heading",
+ NULL,
+ UI_MAX_NAME_STR,
+ "Heading",
+ "Label to insert into the layout for this column");
func = RNA_def_function(srna, "column_flow", "uiLayoutColumnFlow");
RNA_def_int(func, "columns", 0, 0, INT_MAX, "", "Number of columns, 0 is automatic", 0, INT_MAX);
@@ -887,6 +899,20 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common(func);
+ func = RNA_def_function(srna, "prop_decorator", "uiItemDecoratorR");
+ api_ui_item_rna_common(func);
+ RNA_def_int(func,
+ "index",
+ /* RNA_NO_INDEX == -1 */
+ -1,
+ -2,
+ INT_MAX,
+ "",
+ "The index of this button, when set a single member of an array can be accessed, "
+ "when set to -1 all array members are used",
+ -2,
+ INT_MAX);
+
for (int is_menu_hold = 0; is_menu_hold < 2; is_menu_hold++) {
func = (is_menu_hold) ? RNA_def_function(srna, "operator_menu_hold", "rna_uiItemOMenuHold") :
RNA_def_function(srna, "operator", "rna_uiItemO");
@@ -1492,6 +1518,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
func = RNA_def_function(srna, "template_node_link", "uiTemplateNodeLink");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "ntree", "NodeTree", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "node", "Node", "", "");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index c08a95d7e16..d1af3ea7910 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -6063,10 +6063,6 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
prop,
"Undo Legacy",
"Use legacy undo (slower than the new default one, but may be more stable in some cases)");
-
- prop = RNA_def_property(srna, "use_menu_search", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_menu_search", 1);
- RNA_def_property_ui_text(prop, "Menu Search", "Search actions by menus instead of operators");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index b08e48a4b17..04a8500d136 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -45,6 +45,16 @@ static bool rna_XrSessionState_is_running(bContext *C)
# endif
}
+static void rna_XrSessionState_reset_to_base_pose(bContext *C)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = CTX_wm_manager(C);
+ WM_xr_session_base_pose_reset(&wm->xr);
+# else
+ UNUSED_VARS(C);
+# endif
+}
+
# ifdef WITH_XR_OPENXR
static wmXrData *rna_XrSessionState_wm_xr_data_get(PointerRNA *ptr)
{
@@ -197,6 +207,12 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
parm = RNA_def_boolean(func, "result", 0, "Result", "");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "reset_to_base_pose", "rna_XrSessionState_reset_to_base_pose");
+ RNA_def_function_ui_description(func, "Force resetting of position and rotation deltas");
+ RNA_def_function_flag(func, FUNC_NO_SELF);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
prop = RNA_def_property(srna, "viewer_pose_location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 3);
RNA_def_property_float_funcs(prop, "rna_XrSessionState_viewer_pose_location_get", NULL, NULL);
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 275c16873a8..1c2b92383a6 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -244,7 +244,7 @@ ModifierTypeInfo modifierType_Armature = {
/* structName */ "ArmatureModifierData",
/* structSize */ sizeof(ArmatureModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
@@ -253,7 +253,10 @@ ModifierTypeInfo modifierType_Armature = {
/* deformMatrices */ deformMatrices,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ deformMatricesEM,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index bad1d7d3cf9..363fa85c32c 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -791,7 +791,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
return result;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
ArrayModifierData *amd = (ArrayModifierData *)md;
return arrayModifier_doArray(amd, ctx, mesh);
@@ -837,7 +837,10 @@ ModifierTypeInfo modifierType_Array = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index bd2f8a6dca3..a54bb2dfc6f 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -91,7 +91,7 @@ static void requiredDataMask(Object *UNUSED(ob),
/*
* This calls the new bevel code (added since 2.64)
*/
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
BMesh *bm;
@@ -275,7 +275,10 @@ ModifierTypeInfo modifierType_Bevel = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 67610e8cd29..aabdff12e71 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -153,7 +153,7 @@ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
Mesh *result = mesh;
@@ -359,7 +359,10 @@ ModifierTypeInfo modifierType_Boolean = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 3c1a5744b33..920e5eadf04 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -55,7 +55,7 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
return true;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, struct Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct Mesh *mesh)
{
Mesh *result;
BuildModifierData *bmd = (BuildModifierData *)md;
@@ -288,7 +288,10 @@ ModifierTypeInfo modifierType_Build = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index eb6292e5e46..9ef8049071b 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -523,7 +523,7 @@ ModifierTypeInfo modifierType_Cast = {
/* structName */ "CastModifierData",
/* structSize */ sizeof(CastModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
@@ -532,7 +532,10 @@ ModifierTypeInfo modifierType_Cast = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index 0cab6144de8..77f4d543800 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -267,7 +267,10 @@ ModifierTypeInfo modifierType_Cloth = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index e1595488d08..430f8097330 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -254,7 +254,10 @@ ModifierTypeInfo modifierType_Collision = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 52003f8b1d8..0d9a3d87612 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -776,7 +776,10 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index e287685a9e5..14f0d2774a5 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -154,7 +154,7 @@ ModifierTypeInfo modifierType_Curve = {
/* structName */ "CurveModifierData",
/* structSize */ sizeof(CurveModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
@@ -163,7 +163,10 @@ ModifierTypeInfo modifierType_Curve = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index 72cbe197251..b54d5fed390 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -156,7 +156,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
(DT_TYPE_BWEIGHT_VERT | DT_TYPE_BWEIGHT_EDGE | DT_TYPE_CREASE | DT_TYPE_SHARP_EDGE | \
DT_TYPE_LNOR | DT_TYPE_SHARP_FACE)
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me_mod)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me_mod)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *)md;
struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
@@ -225,8 +225,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
else if (result->totvert > HIGH_POLY_WARNING ||
((Mesh *)(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");
+ md, "Source or destination object has a high polygon count, computation might be slow");
}
return result;
@@ -249,7 +248,10 @@ ModifierTypeInfo modifierType_DataTransfer = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index cf07b5460e1..e9d77a699d8 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -89,7 +89,7 @@ static void updateFaceCount(const ModifierEvalContext *ctx,
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData)
{
DecimateModifierData *dmd = (DecimateModifierData *)md;
Mesh *mesh = meshData, *result = NULL;
@@ -228,7 +228,10 @@ ModifierTypeInfo modifierType_Decimate = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 19a4e855153..c8705fa560d 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -427,7 +427,10 @@ ModifierTypeInfo modifierType_Displace = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index d36fce3752b..4dc5d1d7e39 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -101,7 +101,7 @@ static void requiredDataMask(Object *UNUSED(ob),
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
@@ -187,7 +187,10 @@ ModifierTypeInfo modifierType_DynamicPaint = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 69ba4aa2795..fc4091fabf6 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -113,7 +113,7 @@ static void initData(ModifierData *md)
emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
Mesh *result;
EdgeSplitModifierData *emd = (EdgeSplitModifierData *)md;
@@ -142,7 +142,10 @@ ModifierTypeInfo modifierType_EdgeSplit = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index d380747eb31..a3827e249ed 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -1123,7 +1123,7 @@ static ParticleSystemModifierData *findPrecedingParticlesystem(Object *ob, Modif
}
return psmd;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
ExplodeModifierData *emd = (ExplodeModifierData *)md;
ParticleSystemModifierData *psmd = findPrecedingParticlesystem(ctx->object, md);
@@ -1186,7 +1186,10 @@ ModifierTypeInfo modifierType_Explode = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_fluid.c b/source/blender/modifiers/intern/MOD_fluid.c
index 1c2f0a413a7..8ca05f6060b 100644
--- a/source/blender/modifiers/intern/MOD_fluid.c
+++ b/source/blender/modifiers/intern/MOD_fluid.c
@@ -101,7 +101,7 @@ static void requiredDataMask(Object *UNUSED(ob),
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me)
{
#ifndef WITH_FLUID
UNUSED_VARS(md, ctx);
@@ -207,7 +207,10 @@ ModifierTypeInfo modifierType_Fluid = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 1ae2c5e4424..b7ae025fbc2 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -393,7 +393,7 @@ ModifierTypeInfo modifierType_Hook = {
/* structName */ "HookModifierData",
/* structSize */ sizeof(HookModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
@@ -401,7 +401,10 @@ ModifierTypeInfo modifierType_Hook = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index 683696b0725..73c9751bae7 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -814,7 +814,10 @@ ModifierTypeInfo modifierType_LaplacianDeform = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 97e94c46340..2d64227408d 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -580,7 +580,10 @@ ModifierTypeInfo modifierType_LaplacianSmooth = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ init_data,
/* requiredDataMask */ required_data_mask,
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 2b39f40a2b9..c07a012304f 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -137,7 +137,7 @@ ModifierTypeInfo modifierType_Lattice = {
/* structName */ "LatticeModifierData",
/* structSize */ sizeof(LatticeModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
@@ -146,7 +146,10 @@ ModifierTypeInfo modifierType_Lattice = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index 3bdb5a3fd54..f98461fa47e 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -46,14 +46,14 @@
#include "MOD_modifiertypes.h"
-#include "BLI_array_cxx.h"
-#include "BLI_listbase_wrapper.h"
-#include "BLI_vector.h"
+#include "BLI_array.hh"
+#include "BLI_listbase_wrapper.hh"
+#include "BLI_vector.hh"
using BLI::Array;
using BLI::ArrayRef;
using BLI::IndexRange;
-using BLI::IntrusiveListBaseWrapper;
+using BLI::ListBaseWrapper;
using BLI::MutableArrayRef;
using BLI::Vector;
@@ -93,7 +93,7 @@ static void compute_vertex_mask__armature_mode(MDeformVert *dvert,
/* Element i is true if there is a selected bone that uses vertex group i. */
Vector<bool> selected_bone_uses_group;
- for (bDeformGroup *def : IntrusiveListBaseWrapper<bDeformGroup>(ob->defbase)) {
+ for (bDeformGroup *def : ListBaseWrapper<bDeformGroup>(ob->defbase)) {
bPoseChannel *pchan = BKE_pose_channel_find_name(armature_ob->pose, def->name);
bool bone_for_group_exists = pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED);
selected_bone_uses_group.append(bone_for_group_exists);
@@ -293,7 +293,7 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
* 2. Find edges and polygons only using those vertices.
* 3. Create a new mesh that only uses the found vertices, edges and polygons.
*/
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
MaskModifierData *mmd = (MaskModifierData *)md;
Object *ob = ctx->object;
@@ -401,7 +401,10 @@ ModifierTypeInfo modifierType_Mask = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ NULL,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index c2cbddf806c..96e69df1bb5 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -292,7 +292,7 @@ ModifierTypeInfo modifierType_MeshCache = {
/* structName */ "MeshCacheModifierData",
/* structSize */ sizeof(MeshCacheModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
@@ -301,7 +301,10 @@ ModifierTypeInfo modifierType_MeshCache = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index d1fa496c3e5..67eb4766bd6 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -558,7 +558,7 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* structName */ "MeshDeformModifierData",
/* structSize */ sizeof(MeshDeformModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
@@ -567,7 +567,10 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index 7357f18eb6a..fee04217525 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -90,7 +90,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
#ifdef WITH_ALEMBIC
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
@@ -197,7 +197,10 @@ ModifierTypeInfo modifierType_MeshSequenceCache = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 3b3dfa2bda2..f05f12ebfeb 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -100,7 +100,7 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
return result;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
MirrorModifierData *mmd = (MirrorModifierData *)md;
@@ -130,7 +130,10 @@ ModifierTypeInfo modifierType_Mirror = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index f9d53d08c2e..751cd46ac62 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -172,7 +172,7 @@ static Mesh *multires_as_ccg(MultiresModifierData *mmd,
return result;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result = mesh;
#if !defined(WITH_OPENSUBDIV)
@@ -286,7 +286,10 @@ ModifierTypeInfo modifierType_Multires = {
/* deformMatrices */ deformMatrices,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c
index 9be422afab9..84c9fc1d726 100644
--- a/source/blender/modifiers/intern/MOD_none.c
+++ b/source/blender/modifiers/intern/MOD_none.c
@@ -51,7 +51,10 @@ ModifierTypeInfo modifierType_None = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ NULL,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 0b101b26906..ccbc0de900f 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -684,7 +684,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
return normalEditModifier_do((NormalEditModifierData *)md, ctx, ctx->object, mesh);
}
@@ -703,7 +703,10 @@ ModifierTypeInfo modifierType_NormalEdit = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index fddfc74f267..b98dee493ef 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -482,7 +482,7 @@ static Mesh *doOcean(ModifierData *UNUSED(md), const ModifierEvalContext *UNUSED
}
#endif /* WITH_OCEANSIM */
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
@@ -509,7 +509,10 @@ ModifierTypeInfo modifierType_Ocean = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 8a4468ec91e..78e9293effe 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -204,7 +204,7 @@ static void store_float_in_vcol(MLoopCol *vcol, float float_value)
vcol->a = 1.0f;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
@@ -560,7 +560,10 @@ ModifierTypeInfo modifierType_ParticleInstance = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 05bfe9aeff0..03754df45ad 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -264,7 +264,10 @@ ModifierTypeInfo modifierType_ParticleSystem = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 2fa8dc973a1..a693ad4767d 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -136,7 +136,7 @@ static void dualcon_add_quad(void *output_v, const int vert_indices[4])
output->curface++;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
RemeshModifierData *rmd;
DualConOutput *output;
@@ -210,9 +210,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(c
#else /* !WITH_MOD_REMESH */
-static Mesh *applyModifier(ModifierData *UNUSED(md),
- const ModifierEvalContext *UNUSED(ctx),
- Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *UNUSED(md),
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh)
{
return mesh;
}
@@ -233,7 +233,10 @@ ModifierTypeInfo modifierType_Remesh = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index e832a23b4ed..5962df6ce61 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -178,7 +178,7 @@ static void initData(ModifierData *md)
ltmd->merge_dist = 0.01f;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData)
{
Mesh *mesh = meshData;
Mesh *result;
@@ -1171,7 +1171,10 @@ ModifierTypeInfo modifierType_Screw = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index 25f702bf696..8e17d412308 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -122,7 +122,7 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* structName */ "ShapeKeyModifierData",
/* structSize */ sizeof(ShapeKeyModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ NULL,
@@ -131,7 +131,10 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* deformMatrices */ deformMatrices,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ deformMatricesEM,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ NULL,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index 842ec46f364..e686f837cb5 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -204,7 +204,7 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
/* structSize */ sizeof(ShrinkwrapModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs |
- eModifierTypeFlag_AcceptsLattice | eModifierTypeFlag_SupportsEditmode |
+ eModifierTypeFlag_AcceptsVertexCosOnly | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
/* copyData */ modifier_copyData_generic,
@@ -213,7 +213,10 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 65ea6b95824..902037ff939 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -454,7 +454,7 @@ ModifierTypeInfo modifierType_SimpleDeform = {
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs |
- eModifierTypeFlag_AcceptsLattice | eModifierTypeFlag_SupportsEditmode |
+ eModifierTypeFlag_AcceptsVertexCosOnly | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
/* copyData */ modifier_copyData_generic,
@@ -463,7 +463,10 @@ ModifierTypeInfo modifierType_SimpleDeform = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index ec7c2b5b1a4..4c4ff806476 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -1911,7 +1911,7 @@ static void initData(ModifierData *md)
smd->symmetry_axes = MOD_SKIN_SYMM_X;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
Mesh *result;
@@ -1941,7 +1941,10 @@ ModifierTypeInfo modifierType_Skin = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index 2a0376fd291..f40fd22d233 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -237,7 +237,10 @@ ModifierTypeInfo modifierType_Smooth = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index efe6b188fa0..1566f2d378d 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -78,7 +78,7 @@ ModifierTypeInfo modifierType_Softbody = {
/* structName */ "SoftbodyModifierData",
/* structSize */ sizeof(SoftbodyModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_RequiresOriginalData | eModifierTypeFlag_Single |
eModifierTypeFlag_UsesPointCache,
@@ -88,7 +88,10 @@ ModifierTypeInfo modifierType_Softbody = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ NULL,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index fc9719a5fb4..3a86ac43f9b 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -70,14 +70,14 @@ static void requiredDataMask(Object *UNUSED(ob),
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
const SolidifyModifierData *smd = (SolidifyModifierData *)md;
switch (smd->mode) {
case MOD_SOLIDIFY_MODE_EXTRUDE:
- return MOD_solidify_extrude_applyModifier(md, ctx, mesh);
+ return MOD_solidify_extrude_modifyMesh(md, ctx, mesh);
case MOD_SOLIDIFY_MODE_NONMANIFOLD:
- return MOD_solidify_nonmanifold_applyModifier(md, ctx, mesh);
+ return MOD_solidify_nonmanifold_modifyMesh(md, ctx, mesh);
default:
BLI_assert(0);
}
@@ -100,7 +100,10 @@ ModifierTypeInfo modifierType_Solidify = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index fee1b552d89..e842e81f97f 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -183,9 +183,7 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
/** \name Main Solidify Function
* \{ */
-Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- Mesh *mesh)
+Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
const SolidifyModifierData *smd = (SolidifyModifierData *)md;
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index e42207081ed..d237b55e900 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -132,9 +132,9 @@ static int comp_float_int_pair(const void *a, const void *b)
return (int)(x->angle > y->angle) - (int)(x->angle < y->angle);
}
-Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- Mesh *mesh)
+Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
Mesh *result;
const SolidifyModifierData *smd = (SolidifyModifierData *)md;
diff --git a/source/blender/modifiers/intern/MOD_solidify_util.h b/source/blender/modifiers/intern/MOD_solidify_util.h
index 3a9608861dc..6ab4734c451 100644
--- a/source/blender/modifiers/intern/MOD_solidify_util.h
+++ b/source/blender/modifiers/intern/MOD_solidify_util.h
@@ -22,13 +22,13 @@
#define __MOD_SOLIDIFY_UTIL_H__
/* MOD_solidify_extrude.c */
-Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- Mesh *mesh);
+Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh);
/* MOD_solidify_nonmanifold.c */
-Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- Mesh *mesh);
+Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh);
#endif /* __MOD_SOLIDIFY_UTIL_H__ */
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index b3bc5a66e8c..cf31f15e17b 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -206,7 +206,7 @@ static SubsurfRuntimeData *subsurf_ensure_runtime(SubsurfModifierData *smd)
/* Modifier itself. */
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result = mesh;
#if !defined(WITH_OPENSUBDIV)
@@ -290,7 +290,10 @@ ModifierTypeInfo modifierType_Subsurf = {
/* deformMatrices */ deformMatrices,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 0e318e9b092..01c1119566b 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -196,7 +196,10 @@ ModifierTypeInfo modifierType_Surface = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 4ef1f32462a..0f3fbf15d52 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -112,7 +112,7 @@ typedef struct SDefDeformData {
const SDefVert *const bind_verts;
float (*const targetCos)[3];
float (*const vertexCos)[3];
- float(*const weights);
+ float *const weights;
float const strength;
} SDefDeformData;
@@ -1395,7 +1395,10 @@ ModifierTypeInfo modifierType_SurfaceDeform = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 1e6bc2e1819..796f30890da 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -103,7 +103,7 @@ static void initData(ModifierData *md)
tmd->min_vertices = 4;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
TriangulateModifierData *tmd = (TriangulateModifierData *)md;
Mesh *result;
@@ -130,7 +130,10 @@ ModifierTypeInfo modifierType_Triangulate = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL, // requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 242f31b6434..b11669cf8eb 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -303,7 +303,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
return mesh;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
UVProjectModifierData *umd = (UVProjectModifierData *)md;
@@ -327,7 +327,10 @@ ModifierTypeInfo modifierType_UVProject = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index 6545159bdde..b1fdac82886 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -126,7 +126,7 @@ static void uv_warp_compute(void *__restrict userdata,
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
UVWarpModifierData *umd = (UVWarpModifierData *)md;
int numPolys, numLoops;
@@ -259,7 +259,10 @@ ModifierTypeInfo modifierType_UVWarp = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 30d45d1fc65..31ed7f67b47 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -393,7 +393,7 @@ ModifierTypeInfo modifierType_Warp = {
/* structName */ "WarpModifierData",
/* structSize */ sizeof(WarpModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
@@ -401,7 +401,10 @@ ModifierTypeInfo modifierType_Warp = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index fd481018cc2..78dfdfcf403 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -365,7 +365,7 @@ ModifierTypeInfo modifierType_Wave = {
/* structName */ "WaveModifierData",
/* structSize */ sizeof(WaveModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
@@ -374,7 +374,10 @@ ModifierTypeInfo modifierType_Wave = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
index 04b503e588b..d26eadecbf1 100644
--- a/source/blender/modifiers/intern/MOD_weighted_normal.c
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -546,7 +546,7 @@ static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalD
apply_weights_vertex_normal(wnmd, wn_data);
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
Object *ob = ctx->object;
@@ -714,7 +714,10 @@ ModifierTypeInfo modifierType_WeightedNormal = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index 006191e29fc..d7c9945f87b 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -164,7 +164,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return (wmd->defgrp_name[0] == '\0');
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
BLI_assert(mesh != NULL);
@@ -315,7 +315,10 @@ ModifierTypeInfo modifierType_WeightVGEdit = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index f256045f53a..566953cd862 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -210,7 +210,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return (wmd->defgrp_name_a[0] == '\0');
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
BLI_assert(mesh != NULL);
@@ -442,7 +442,10 @@ ModifierTypeInfo modifierType_WeightVGMix = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 7b7aaaeb654..844ad59eb02 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -410,7 +410,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return (wmd->proximity_ob_target == NULL);
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
BLI_assert(mesh != NULL);
@@ -642,7 +642,10 @@ ModifierTypeInfo modifierType_WeightVGProximity = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
index 90b71b2d504..2743110cfdf 100644
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ b/source/blender/modifiers/intern/MOD_weld.c
@@ -1902,7 +1902,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex
return result;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
WeldModifierData *wmd = (WeldModifierData *)md;
return weldModifier_doWeld(wmd, ctx, mesh);
@@ -1944,7 +1944,10 @@ ModifierTypeInfo modifierType_Weld = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 04473b30585..51e9949ce17 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -99,9 +99,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
return result;
}
-static Mesh *applyModifier(ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const struct ModifierEvalContext *ctx, struct Mesh *mesh)
{
return WireframeModifier_do((WireframeModifierData *)md, ctx->object, mesh);
}
@@ -119,7 +117,10 @@ ModifierTypeInfo modifierType_Wireframe = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index a2f825ee454..80bf0f7c5e2 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -21,8 +21,10 @@
set(INC
.
composite
+ function
intern
shader
+ simulation
texture
../blenkernel
../blenlib
@@ -127,6 +129,13 @@ set(SRC
composite/node_composite_tree.c
composite/node_composite_util.c
+ function/nodes/node_fn_boolean_math.cc
+ function/nodes/node_fn_combine_strings.cc
+ function/nodes/node_fn_float_compare.cc
+ function/nodes/node_fn_group_instance_id.cc
+ function/nodes/node_fn_switch.cc
+ function/node_function_util.cc
+
shader/nodes/node_shader_add_shader.c
shader/nodes/node_shader_ambient_occlusion.c
shader/nodes/node_shader_attribute.c
@@ -220,6 +229,22 @@ set(SRC
shader/node_shader_tree.c
shader/node_shader_util.c
+ simulation/nodes/node_sim_common.cc
+ simulation/nodes/node_sim_emit_particles.cc
+ simulation/nodes/node_sim_execute_condition.cc
+ simulation/nodes/node_sim_force.cc
+ simulation/nodes/node_sim_multi_execute.cc
+ simulation/nodes/node_sim_particle_attribute.cc
+ simulation/nodes/node_sim_particle_birth_event.cc
+ simulation/nodes/node_sim_particle_mesh_collision_event.cc
+ simulation/nodes/node_sim_particle_mesh_emitter.cc
+ simulation/nodes/node_sim_particle_simulation.cc
+ simulation/nodes/node_sim_particle_time_step_event.cc
+ simulation/nodes/node_sim_set_particle_attribute.cc
+ simulation/nodes/node_sim_simulation_time.cc
+ simulation/node_simulation_tree.cc
+ simulation/node_simulation_util.cc
+
texture/nodes/node_texture_at.c
texture/nodes/node_texture_bricks.c
texture/nodes/node_texture_checker.c
@@ -252,12 +277,16 @@ set(SRC
intern/node_util.c
composite/node_composite_util.h
+ function/node_function_util.h
shader/node_shader_util.h
+ simulation/node_simulation_util.h
texture/node_texture_util.h
NOD_common.h
NOD_composite.h
+ NOD_function.h
NOD_shader.h
+ NOD_simulation.h
NOD_socket.h
NOD_static_types.h
NOD_texture.h
diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h
index 26c78eab4ec..dcc4f4d0b76 100644
--- a/source/blender/nodes/NOD_common.h
+++ b/source/blender/nodes/NOD_common.h
@@ -26,6 +26,10 @@
#include "BKE_node.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void register_node_type_frame(void);
void register_node_type_reroute(void);
@@ -42,4 +46,8 @@ struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char
void node_group_input_update(struct bNodeTree *ntree, struct bNode *node);
void node_group_output_update(struct bNodeTree *ntree, struct bNode *node);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __NOD_COMMON_H__ */
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
new file mode 100644
index 00000000000..377ae8bfb84
--- /dev/null
+++ b/source/blender/nodes/NOD_function.h
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NOD_FUNCTION_H__
+#define __NOD_FUNCTION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void register_node_type_fn_boolean_math(void);
+void register_node_type_fn_float_compare(void);
+void register_node_type_fn_switch(void);
+void register_node_type_fn_group_instance_id(void);
+void register_node_type_fn_combine_strings(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NOD_FUNCTION_H__ */
diff --git a/source/blender/nodes/NOD_simulation.h b/source/blender/nodes/NOD_simulation.h
new file mode 100644
index 00000000000..2947d38fe83
--- /dev/null
+++ b/source/blender/nodes/NOD_simulation.h
@@ -0,0 +1,47 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NOD_SIMULATION_H__
+#define __NOD_SIMULATION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct bNodeTreeType *ntreeType_Simulation;
+
+void register_node_tree_type_sim(void);
+
+void register_node_type_sim_group(void);
+
+void register_node_type_sim_particle_simulation(void);
+void register_node_type_sim_force(void);
+void register_node_type_sim_set_particle_attribute(void);
+void register_node_type_sim_particle_birth_event(void);
+void register_node_type_sim_particle_time_step_event(void);
+void register_node_type_sim_execute_condition(void);
+void register_node_type_sim_multi_execute(void);
+void register_node_type_sim_particle_mesh_emitter(void);
+void register_node_type_sim_particle_mesh_collision_event(void);
+void register_node_type_sim_emit_particles(void);
+void register_node_type_sim_time(void);
+void register_node_type_sim_particle_attribute(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NOD_SIMULATION_H__ */
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 7fec3324aab..91aa11566d3 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -258,6 +258,26 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_NOISE, 0, "TEX_NO
DefNode(TextureNode, TEX_NODE_PROC+TEX_STUCCI, 0, "TEX_STUCCI", TexStucci, "Stucci", "" )
DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DISTNOISE", TexDistNoise, "Distorted Noise", "" )
+DefNode(SimulationNode, SIM_NODE_PARTICLE_SIMULATION, 0, "PARTICLE_SIMULATION", ParticleSimulation, "Particle Simulation", "")
+DefNode(SimulationNode, SIM_NODE_FORCE, 0, "FORCE", Force, "Force", "")
+DefNode(SimulationNode, SIM_NODE_SET_PARTICLE_ATTRIBUTE, def_sim_set_particle_attribute, "SET_PARTICLE_ATTRIBUTE", SetParticleAttribute, "Set Particle Attribute", "")
+DefNode(SimulationNode, SIM_NODE_PARTICLE_BIRTH_EVENT, 0, "PARTICLE_BIRTH_EVENT", ParticleBirthEvent, "Particle Birth Event", "")
+DefNode(SimulationNode, SIM_NODE_PARTICLE_TIME_STEP_EVENT, def_sim_particle_time_step_event, "PARTICLE_TIME_STEP_EVENT", ParticleTimeStepEvent, "Particle Time Step Event", "")
+DefNode(SimulationNode, SIM_NODE_EXECUTE_CONDITION, 0, "EXECUTE_CONDITION", ExecuteCondition, "Execute Condition", "")
+DefNode(SimulationNode, SIM_NODE_MULTI_EXECUTE, 0, "MULTI_EXECUTE", MultiExecute, "Multi Execute", "")
+DefNode(SimulationNode, SIM_NODE_PARTICLE_MESH_EMITTER, 0, "PARTICLE_MESH_EMITTER", ParticleMeshEmitter, "Particle Mesh Emitter", "")
+DefNode(SimulationNode, SIM_NODE_PARTICLE_MESH_COLLISION_EVENT, 0, "PARTICLE_MESH_COLLISION_EVENT", ParticleMeshCollisionEvent, "Particle Mesh Collision Event", "")
+DefNode(SimulationNode, SIM_NODE_EMIT_PARTICLES, 0, "EMIT_PARTICLES", EmitParticles, "Emit Particles", "")
+DefNode(SimulationNode, SIM_NODE_TIME, def_sim_time, "TIME", Time, "Time", "")
+DefNode(SimulationNode, SIM_NODE_PARTICLE_ATTRIBUTE, def_sim_particle_attribute, "PARTICLE_ATTRIBUTE", ParticleAttribute, "Particle Attribute", "")
+
+DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
+DefNode(FunctionNode, FN_NODE_FLOAT_COMPARE, def_float_compare, "FLOAT_COMPARE", FloatCompare, "Float Compare", "")
+DefNode(FunctionNode, FN_NODE_SWITCH, def_fn_switch, "SWITCH", Switch, "Switch", "")
+DefNode(FunctionNode, FN_NODE_GROUP_INSTANCE_ID, 0, "GROUP_INSTANCE_ID", GroupInstanceID, "Group Instance ID", "")
+DefNode(FunctionNode, FN_NODE_COMBINE_STRINGS, 0, "COMBINE_STRINGS", CombineStrings, "Combine Strings", "")
+
+
/* undefine macros */
#undef DefNode
diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc
new file mode 100644
index 00000000000..0927ba335fe
--- /dev/null
+++ b/source/blender/nodes/function/node_function_util.cc
@@ -0,0 +1,30 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_function_util.h"
+#include "node_util.h"
+
+bool fn_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
+{
+ /* Function nodes are only supported in simulation node trees so far. */
+ return STREQ(ntree->idname, "SimulationNodeTree");
+}
+
+void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+{
+ node_type_base(ntype, type, name, nclass, flag);
+ ntype->poll = fn_node_poll_default;
+}
diff --git a/source/blender/nodes/function/node_function_util.h b/source/blender/nodes/function/node_function_util.h
new file mode 100644
index 00000000000..85e252f9bdd
--- /dev/null
+++ b/source/blender/nodes/function/node_function_util.h
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NODE_FUNCTION_UTIL_H__
+#define __NODE_FUNCTION_UTIL_H__
+
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_node_types.h"
+
+#include "BKE_node.h"
+
+#include "BLT_translation.h"
+
+#include "NOD_function.h"
+
+#include "node_util.h"
+
+void fn_node_type_base(
+ struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+bool fn_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
+
+#endif /* __NODE_FUNCTION_UTIL_H__ */
diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
new file mode 100644
index 00000000000..615ad4c6733
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -0,0 +1,62 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "RNA_enum_types.h"
+
+#include "node_function_util.h"
+
+static bNodeSocketTemplate fn_node_boolean_math_in[] = {
+ {SOCK_BOOLEAN, N_("Boolean")},
+ {SOCK_BOOLEAN, N_("Boolean")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate fn_node_boolean_math_out[] = {
+ {SOCK_BOOLEAN, N_("Boolean")},
+ {-1, ""},
+};
+
+static void node_boolean_math_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
+
+ nodeSetSocketAvailability(sockB,
+ ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR));
+}
+
+static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+{
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_boolean_math_items, node->custom1, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+void register_node_type_fn_boolean_math()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", 0, 0);
+ node_type_socket_templates(&ntype, fn_node_boolean_math_in, fn_node_boolean_math_out);
+ node_type_label(&ntype, node_boolean_math_label);
+ node_type_update(&ntype, node_boolean_math_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_combine_strings.cc b/source/blender/nodes/function/nodes/node_fn_combine_strings.cc
new file mode 100644
index 00000000000..1b6091451d9
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_combine_strings.cc
@@ -0,0 +1,21 @@
+#include "node_function_util.h"
+
+static bNodeSocketTemplate fn_node_combine_strings_in[] = {
+ {SOCK_STRING, N_("A")},
+ {SOCK_STRING, N_("B")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate fn_node_combine_strings_out[] = {
+ {SOCK_STRING, N_("Result")},
+ {-1, ""},
+};
+
+void register_node_type_fn_combine_strings()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_COMBINE_STRINGS, "Combine Strings", 0, 0);
+ node_type_socket_templates(&ntype, fn_node_combine_strings_in, fn_node_combine_strings_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
new file mode 100644
index 00000000000..9788402850b
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
@@ -0,0 +1,66 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "RNA_enum_types.h"
+
+#include "node_function_util.h"
+
+static bNodeSocketTemplate fn_node_float_compare_in[] = {
+ {SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_FLOAT, N_("Epsilon"), 0.001f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate fn_node_float_compare_out[] = {
+ {SOCK_BOOLEAN, N_("Result")},
+ {-1, ""},
+};
+
+static void node_float_compare_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockEpsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
+
+ nodeSetSocketAvailability(
+ sockEpsilon, ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL));
+}
+
+static void node_float_compare_label(bNodeTree *UNUSED(ntree),
+ bNode *node,
+ char *label,
+ int maxlen)
+{
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_float_compare_items, node->custom1, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+void register_node_type_fn_float_compare()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_FLOAT_COMPARE, "Boolean Math", 0, 0);
+ node_type_socket_templates(&ntype, fn_node_float_compare_in, fn_node_float_compare_out);
+ node_type_label(&ntype, node_float_compare_label);
+ node_type_update(&ntype, node_float_compare_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
new file mode 100644
index 00000000000..2ac86ee2407
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
@@ -0,0 +1,15 @@
+#include "node_function_util.h"
+
+static bNodeSocketTemplate fn_node_group_instance_id_out[] = {
+ {SOCK_STRING, N_("Identifier")},
+ {-1, ""},
+};
+
+void register_node_type_fn_group_instance_id()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_GROUP_INSTANCE_ID, "Group Instance ID", 0, 0);
+ node_type_socket_templates(&ntype, nullptr, fn_node_group_instance_id_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_switch.cc b/source/blender/nodes/function/nodes/node_fn_switch.cc
new file mode 100644
index 00000000000..cb721058875
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_switch.cc
@@ -0,0 +1,76 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "node_function_util.h"
+
+static bNodeSocketTemplate fn_node_switch_in[] = {
+ {SOCK_BOOLEAN, N_("Switch")},
+
+ {SOCK_FLOAT, N_("If False"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_INT, N_("If False"), 0, 0, 0, 0, -10000, 10000},
+ {SOCK_BOOLEAN, N_("If False")},
+ {SOCK_VECTOR, N_("If False"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_STRING, N_("If False")},
+ {SOCK_RGBA, N_("If False"), 0.8f, 0.8f, 0.8f, 1.0f},
+ {SOCK_OBJECT, N_("If False")},
+ {SOCK_IMAGE, N_("If False")},
+
+ {SOCK_FLOAT, N_("If True"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_INT, N_("If True"), 0, 0, 0, 0, -10000, 10000},
+ {SOCK_BOOLEAN, N_("If True")},
+ {SOCK_VECTOR, N_("If True"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_STRING, N_("If True")},
+ {SOCK_RGBA, N_("If True"), 0.8f, 0.8f, 0.8f, 1.0f},
+ {SOCK_OBJECT, N_("If True")},
+ {SOCK_IMAGE, N_("If True")},
+
+ {-1, ""},
+};
+
+static bNodeSocketTemplate fn_node_switch_out[] = {
+ {SOCK_FLOAT, N_("Result")},
+ {SOCK_INT, N_("Result")},
+ {SOCK_BOOLEAN, N_("Result")},
+ {SOCK_VECTOR, N_("Result")},
+ {SOCK_STRING, N_("Result")},
+ {SOCK_RGBA, N_("Result")},
+ {SOCK_OBJECT, N_("Result")},
+ {SOCK_IMAGE, N_("Result")},
+ {-1, ""},
+};
+
+static void fn_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ int index = 0;
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ nodeSetSocketAvailability(sock, index == 0 || sock->type == node->custom1);
+ index++;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ nodeSetSocketAvailability(sock, sock->type == node->custom1);
+ }
+}
+
+void register_node_type_fn_switch()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_SWITCH, "Switch", 0, 0);
+ node_type_socket_templates(&ntype, fn_node_switch_in, fn_node_switch_out);
+ node_type_update(&ntype, fn_node_switch_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/node_common.h b/source/blender/nodes/intern/node_common.h
index c3314ae3c28..7810e9f1f14 100644
--- a/source/blender/nodes/intern/node_common.h
+++ b/source/blender/nodes/intern/node_common.h
@@ -26,6 +26,10 @@
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bNodeTree;
void node_group_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
@@ -33,4 +37,8 @@ bool node_group_poll_instance(struct bNode *node, struct bNodeTree *nodetree);
void ntree_update_reroute_nodes(struct bNodeTree *ntree);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.c
index 199b469781d..668dd3829cc 100644
--- a/source/blender/nodes/intern/node_socket.c
+++ b/source/blender/nodes/intern/node_socket.c
@@ -30,6 +30,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_lib_id.h"
#include "BKE_node.h"
#include "RNA_access.h"
@@ -259,6 +260,22 @@ void node_socket_init_default_value(bNodeSocket *sock)
sock->default_value = dval;
break;
}
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *dval = MEM_callocN(sizeof(bNodeSocketValueObject),
+ "node socket value object");
+ dval->value = NULL;
+
+ sock->default_value = dval;
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *dval = MEM_callocN(sizeof(bNodeSocketValueImage),
+ "node socket value image");
+ dval->value = NULL;
+
+ sock->default_value = dval;
+ break;
+ }
}
}
@@ -317,6 +334,20 @@ void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from)
*toval = *fromval;
break;
}
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *toval = to->default_value;
+ bNodeSocketValueObject *fromval = from->default_value;
+ *toval = *fromval;
+ id_us_plus(&toval->value->id);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *toval = to->default_value;
+ bNodeSocketValueImage *fromval = from->default_value;
+ *toval = *fromval;
+ id_us_plus(&toval->value->id);
+ break;
+ }
}
to->flag |= (from->flag & SOCK_HIDE_VALUE);
@@ -467,6 +498,19 @@ static bNodeSocketType *make_socket_type_virtual(void)
return stype;
}
+static bNodeSocketType *make_socket_type_effector(int type)
+{
+ bNodeSocketType *stype = make_standard_socket_type(type, PROP_NONE);
+ stype->input_link_limit = 0xFFF;
+ return stype;
+}
+
+static bNodeSocketType *make_socket_type_control_flow(int type)
+{
+ bNodeSocketType *stype = make_standard_socket_type(type, PROP_NONE);
+ return stype;
+}
+
void register_standard_node_socket_types(void)
{
/* draw callbacks are set in drawnode.c to avoid bad-level calls */
@@ -499,5 +543,15 @@ void register_standard_node_socket_types(void)
nodeRegisterSocketType(make_standard_socket_type(SOCK_SHADER, PROP_NONE));
+ nodeRegisterSocketType(make_standard_socket_type(SOCK_OBJECT, PROP_NONE));
+
+ nodeRegisterSocketType(make_standard_socket_type(SOCK_IMAGE, PROP_NONE));
+
+ nodeRegisterSocketType(make_socket_type_effector(SOCK_EMITTERS));
+ nodeRegisterSocketType(make_socket_type_effector(SOCK_EVENTS));
+ nodeRegisterSocketType(make_socket_type_effector(SOCK_FORCES));
+
+ nodeRegisterSocketType(make_socket_type_control_flow(SOCK_CONTROL_FLOW));
+
nodeRegisterSocketType(make_socket_type_virtual());
}
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
index a7f09d24a70..61f8fe6809d 100644
--- a/source/blender/nodes/intern/node_util.h
+++ b/source/blender/nodes/intern/node_util.h
@@ -38,6 +38,10 @@
#include "RNA_access.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bNode;
struct bNodeTree;
@@ -103,4 +107,8 @@ void node_socket_set_vector(struct bNodeTree *ntree,
struct bNodeSocket *sock,
const float *value);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 93d03720058..4464a61c48c 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -32,6 +32,11 @@ bool sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
return STREQ(ntree->idname, "ShaderNodeTree");
}
+static bool sh_fn_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
+{
+ return STREQ(ntree->idname, "ShaderNodeTree") || STREQ(ntree->idname, "SimulationNodeTree");
+}
+
void sh_node_type_base(
struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
{
@@ -42,6 +47,12 @@ void sh_node_type_base(
ntype->update_internal_links = node_update_internal_links_default;
}
+void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+{
+ sh_node_type_base(ntype, type, name, nclass, flag);
+ ntype->poll = sh_fn_poll_default;
+}
+
/* ****** */
void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index 8d525c8f23c..8834de0633e 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -72,6 +72,8 @@
bool sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
void sh_node_type_base(
struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void sh_fn_node_type_base(
+ struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
/* ********* exec data struct, remains internal *********** */
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c
index d8f560277f2..cc1968cb1b1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c
@@ -46,7 +46,7 @@ void register_node_type_sh_brightcontrast(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_brightcontrast_in, sh_node_brightcontrast_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.c b/source/blender/nodes/shader/nodes/node_shader_clamp.c
index c49cfcea8d3..808f9686f0a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.c
@@ -54,7 +54,7 @@ void register_node_type_sh_clamp(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_clamp_in, sh_node_clamp_out);
node_type_init(&ntype, node_shader_init_clamp);
node_type_gpu(&ntype, gpu_shader_clamp);
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
index b48838e5f56..747979522d1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c
@@ -62,7 +62,7 @@ void register_node_type_sh_gamma(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
index 7a05fc95eec..57ef51c65f6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
@@ -89,7 +89,7 @@ void register_node_type_sh_hue_sat(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_hue_sat_in, sh_node_hue_sat_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_hue_sat);
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.c
index 0d6709a1968..19fa0b0309d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_invert.c
+++ b/source/blender/nodes/shader/nodes/node_shader_invert.c
@@ -69,7 +69,7 @@ void register_node_type_sh_invert(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_invert_in, sh_node_invert_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_invert);
node_type_gpu(&ntype, gpu_shader_invert);
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.c b/source/blender/nodes/shader/nodes/node_shader_map_range.c
index d59540cb8fa..5db7983e752 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.c
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.c
@@ -81,7 +81,7 @@ void register_node_type_sh_map_range(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_map_range_in, sh_node_map_range_out);
node_type_init(&ntype, node_shader_init_map_range);
node_type_update(&ntype, node_shader_update_map_range);
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c
index 08578e0e11e..8abebbf5081 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_math.c
@@ -105,7 +105,7 @@ void register_node_type_sh_math(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_math_in, sh_node_math_out);
node_type_label(&ntype, node_math_label);
node_type_gpu(&ntype, gpu_shader_math);
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
index 9c318073304..93e88664d1a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
@@ -107,7 +107,7 @@ void register_node_type_sh_mix_rgb(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_mix_rgb_in, sh_node_mix_rgb_out);
node_type_label(&ntype, node_blend_label);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_mix_rgb);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
index 951755be4f3..2c9b77530a2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
@@ -61,7 +61,7 @@ void register_node_type_sh_sephsv(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_sephsv_in, sh_node_sephsv_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_sephsv);
node_type_gpu(&ntype, gpu_shader_sephsv);
@@ -109,7 +109,7 @@ void register_node_type_sh_combhsv(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_combhsv_in, sh_node_combhsv_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_combhsv);
node_type_gpu(&ntype, gpu_shader_combhsv);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
index f10f80d5c2d..d0dc45dcedd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
@@ -63,7 +63,7 @@ void register_node_type_sh_seprgb(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_seprgb_in, sh_node_seprgb_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_seprgb);
node_type_gpu(&ntype, gpu_shader_seprgb);
@@ -113,7 +113,7 @@ void register_node_type_sh_combrgb(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_combrgb_in, sh_node_combrgb_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_combrgb);
node_type_gpu(&ntype, gpu_shader_combrgb);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
index 55d5084b132..429b1a3e818 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
@@ -48,7 +48,7 @@ void register_node_type_sh_sepxyz(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_sepxyz_in, sh_node_sepxyz_out);
node_type_gpu(&ntype, gpu_shader_sepxyz);
@@ -80,7 +80,7 @@ void register_node_type_sh_combxyz(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_combxyz_in, sh_node_combxyz_out);
node_type_gpu(&ntype, gpu_shader_combxyz);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index fa98f9efb74..420c5b75926 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -137,6 +137,9 @@ static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *nod
nodeSetSocketAvailability(inGainSock,
tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL ||
tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
+
+ bNodeSocket *outFacSock = nodeFindSocket(node, SOCK_OUT, "Fac");
+ node_sock_label(outFacSock, "Height");
}
void register_node_type_sh_tex_musgrave(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
index 7b67c2d1f2e..67268c102c5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -91,7 +91,7 @@ void register_node_type_sh_tex_noise(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0);
node_type_socket_templates(&ntype, sh_node_tex_noise_in, sh_node_tex_noise_out);
node_type_init(&ntype, node_shader_init_tex_noise);
node_type_storage(
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
index 1789dc44bf1..817ccdc8b6a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
@@ -72,7 +72,8 @@ void register_node_type_sh_tex_white_noise(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0);
+ sh_fn_node_type_base(
+ &ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0);
node_type_socket_templates(&ntype, sh_node_tex_white_noise_in, sh_node_tex_white_noise_out);
node_type_init(&ntype, node_shader_init_tex_white_noise);
node_type_gpu(&ntype, gpu_shader_tex_white_noise);
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
index 49f9befdce3..20f280d00c3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
@@ -125,7 +125,7 @@ void register_node_type_sh_valtorgb(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_valtorgb_in, sh_node_valtorgb_out);
node_type_init(&ntype, node_shader_init_valtorgb);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.c b/source/blender/nodes/shader/nodes/node_shader_vector_math.c
index 3a6e273eb20..b719fe03d9b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.c
@@ -134,7 +134,7 @@ void register_node_type_sh_vect_math(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0);
node_type_socket_templates(&ntype, sh_node_vector_math_in, sh_node_vector_math_out);
node_type_label(&ntype, node_vector_math_label);
node_type_gpu(&ntype, gpu_shader_vector_math);
diff --git a/source/blender/nodes/simulation/node_simulation_tree.cc b/source/blender/nodes/simulation/node_simulation_tree.cc
new file mode 100644
index 00000000000..3f0e70259d6
--- /dev/null
+++ b/source/blender/nodes/simulation/node_simulation_tree.cc
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "NOD_simulation.h"
+
+#include "BKE_node.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_node_types.h"
+
+#include "RNA_access.h"
+
+bNodeTreeType *ntreeType_Simulation;
+
+void register_node_tree_type_sim(void)
+{
+ bNodeTreeType *tt = ntreeType_Simulation = (bNodeTreeType *)MEM_callocN(
+ sizeof(bNodeTreeType), "simulation node tree type");
+ tt->type = NTREE_SIMULATION;
+ strcpy(tt->idname, "SimulationNodeTree");
+ strcpy(tt->ui_name, N_("Simulation Editor"));
+ tt->ui_icon = 0; /* defined in drawnode.c */
+ strcpy(tt->ui_description, N_("Simulation nodes"));
+ tt->rna_ext.srna = &RNA_SimulationNodeTree;
+
+ ntreeTypeAdd(tt);
+}
diff --git a/source/blender/nodes/simulation/node_simulation_util.cc b/source/blender/nodes/simulation/node_simulation_util.cc
new file mode 100644
index 00000000000..ae875335da8
--- /dev/null
+++ b/source/blender/nodes/simulation/node_simulation_util.cc
@@ -0,0 +1,29 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+#include "node_util.h"
+
+bool sim_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
+{
+ return STREQ(ntree->idname, "SimulationNodeTree");
+}
+
+void sim_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+{
+ node_type_base(ntype, type, name, nclass, flag);
+ ntype->poll = sim_node_poll_default;
+}
diff --git a/source/blender/nodes/simulation/node_simulation_util.h b/source/blender/nodes/simulation/node_simulation_util.h
new file mode 100644
index 00000000000..adbe2ad5e8f
--- /dev/null
+++ b/source/blender/nodes/simulation/node_simulation_util.h
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NODE_SIM_UTIL_H__
+#define __NODE_SIM_UTIL_H__
+
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_node_types.h"
+
+#include "BKE_node.h"
+
+#include "BLT_translation.h"
+
+#include "NOD_simulation.h"
+
+#include "node_util.h"
+
+void sim_node_type_base(
+ struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+bool sim_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
+
+#endif /* __NODE_SIM_UTIL_H__ */
diff --git a/source/blender/nodes/simulation/nodes/node_sim_common.cc b/source/blender/nodes/simulation/nodes/node_sim_common.cc
new file mode 100644
index 00000000000..fbc03905d4f
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_common.cc
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_node.h"
+
+#include "NOD_simulation.h"
+
+#include "NOD_common.h"
+#include "node_common.h"
+#include "node_simulation_util.h"
+
+void register_node_type_sim_group(void)
+{
+ static bNodeType ntype;
+
+ node_type_base_custom(&ntype, "SimulationNodeGroup", "Group", 0, 0);
+ ntype.type = NODE_GROUP;
+ ntype.poll = sim_node_poll_default;
+ ntype.poll_instance = node_group_poll_instance;
+ ntype.insert_link = node_insert_link_default;
+ ntype.update_internal_links = node_update_internal_links_default;
+ ntype.rna_ext.srna = RNA_struct_find("SimulationNodeGroup");
+ BLI_assert(ntype.rna_ext.srna != NULL);
+ RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
+
+ node_type_socket_templates(&ntype, NULL, NULL);
+ node_type_size(&ntype, 140, 60, 400);
+ node_type_label(&ntype, node_group_label);
+ node_type_group_update(&ntype, node_group_update);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_emit_particles.cc b/source/blender/nodes/simulation/nodes/node_sim_emit_particles.cc
new file mode 100644
index 00000000000..e23984dbf34
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_emit_particles.cc
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_emit_particle_in[] = {
+ {SOCK_INT, N_("Amount"), 10, 0, 0, 0, 0, 10000000},
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_emit_particle_out[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {SOCK_EMITTERS, N_("Emitter")},
+ {-1, ""},
+};
+
+void register_node_type_sim_emit_particles()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_EMIT_PARTICLES, "Emit Particles", 0, 0);
+ node_type_socket_templates(&ntype, sim_node_emit_particle_in, sim_node_emit_particle_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_execute_condition.cc b/source/blender/nodes/simulation/nodes/node_sim_execute_condition.cc
new file mode 100644
index 00000000000..69f30d1ad0d
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_execute_condition.cc
@@ -0,0 +1,39 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_execute_condition_in[] = {
+ {SOCK_BOOLEAN, N_("Condition")},
+ {SOCK_CONTROL_FLOW, N_("If True")},
+ {SOCK_CONTROL_FLOW, N_("If False")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_execute_condition_out[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+void register_node_type_sim_execute_condition()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_EXECUTE_CONDITION, "Execute Condition", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_execute_condition_in, sim_node_execute_condition_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_force.cc b/source/blender/nodes/simulation/nodes/node_sim_force.cc
new file mode 100644
index 00000000000..eccd2e4e2ab
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_force.cc
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_force_in[] = {
+ {SOCK_VECTOR, N_("Force"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_force_out[] = {
+ {SOCK_FORCES, N_("Force")},
+ {-1, ""},
+};
+
+void register_node_type_sim_force()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_FORCE, "Force", 0, 0);
+ node_type_socket_templates(&ntype, sim_node_force_in, sim_node_force_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_multi_execute.cc b/source/blender/nodes/simulation/nodes/node_sim_multi_execute.cc
new file mode 100644
index 00000000000..5944db7e2bc
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_multi_execute.cc
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_multi_execute_in[] = {
+ {SOCK_CONTROL_FLOW, "1"},
+ {SOCK_CONTROL_FLOW, "2"},
+ {SOCK_CONTROL_FLOW, "3"},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_multi_execute_out[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+void register_node_type_sim_multi_execute()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_MULTI_EXECUTE, "Multi Execute", 0, 0);
+ node_type_socket_templates(&ntype, sim_node_multi_execute_in, sim_node_multi_execute_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_attribute.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_attribute.cc
new file mode 100644
index 00000000000..b6b67ee334e
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_attribute.cc
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_particle_attribute_in[] = {
+ {SOCK_STRING, N_("Name")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_attribute_out[] = {
+ {SOCK_FLOAT, N_("Float")},
+ {SOCK_INT, N_("Int")},
+ {SOCK_BOOLEAN, N_("Boolean")},
+ {SOCK_VECTOR, N_("Vector")},
+ {SOCK_RGBA, N_("Color")},
+ {SOCK_OBJECT, N_("Object")},
+ {SOCK_IMAGE, N_("Image")},
+ {-1, ""},
+};
+
+static void sim_node_particle_attribute_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ nodeSetSocketAvailability(sock, sock->type == node->custom1);
+ }
+}
+
+void register_node_type_sim_particle_attribute()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_PARTICLE_ATTRIBUTE, "Particle Attribute", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_particle_attribute_in, sim_node_particle_attribute_out);
+ node_type_update(&ntype, sim_node_particle_attribute_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_birth_event.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_birth_event.cc
new file mode 100644
index 00000000000..8332a3ecd9f
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_birth_event.cc
@@ -0,0 +1,37 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_particle_birth_event_in[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_birth_event_out[] = {
+ {SOCK_EVENTS, N_("Event")},
+ {-1, ""},
+};
+
+void register_node_type_sim_particle_birth_event()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_PARTICLE_BIRTH_EVENT, "Particle Birth Event", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_particle_birth_event_in, sim_node_particle_birth_event_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_collision_event.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_collision_event.cc
new file mode 100644
index 00000000000..48671172136
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_collision_event.cc
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_particle_mesh_collision_event_in[] = {
+ {SOCK_OBJECT, N_("Object")},
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_mesh_collision_event_out[] = {
+ {SOCK_EVENTS, N_("Event")},
+ {-1, ""},
+};
+
+void register_node_type_sim_particle_mesh_collision_event()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(
+ &ntype, SIM_NODE_PARTICLE_MESH_COLLISION_EVENT, "Particle Mesh Collision Event", 0, 0);
+ node_type_socket_templates(&ntype,
+ sim_node_particle_mesh_collision_event_in,
+ sim_node_particle_mesh_collision_event_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc
new file mode 100644
index 00000000000..2de7be2d3eb
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+#include "float.h"
+
+static bNodeSocketTemplate sim_node_particle_mesh_emitter_in[] = {
+ {SOCK_OBJECT, N_("Object")},
+ {SOCK_FLOAT, N_("Rate"), 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_mesh_emitter_out[] = {
+ {SOCK_EMITTERS, N_("Emitter")},
+ {-1, ""},
+};
+
+void register_node_type_sim_particle_mesh_emitter()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_PARTICLE_MESH_EMITTER, "Mesh Emitter", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_particle_mesh_emitter_in, sim_node_particle_mesh_emitter_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_simulation.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_simulation.cc
new file mode 100644
index 00000000000..159c9b23da1
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_simulation.cc
@@ -0,0 +1,39 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_particle_simulation_in[] = {
+ {SOCK_EMITTERS, N_("Emitters")},
+ {SOCK_EVENTS, N_("Events")},
+ {SOCK_FORCES, N_("Forces")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_simulation_out[] = {
+ {-1, ""},
+};
+
+void register_node_type_sim_particle_simulation()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(
+ &ntype, SIM_NODE_PARTICLE_SIMULATION, "Particle Simulation", NODE_CLASS_OUTPUT, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_particle_simulation_in, sim_node_particle_simulation_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_time_step_event.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_time_step_event.cc
new file mode 100644
index 00000000000..cda8ddeb644
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_time_step_event.cc
@@ -0,0 +1,37 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_particle_time_step_event_in[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_time_step_event_out[] = {
+ {SOCK_EVENTS, N_("Event")},
+ {-1, ""},
+};
+
+void register_node_type_sim_particle_time_step_event()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_PARTICLE_TIME_STEP_EVENT, "Particle Time Step Event", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_particle_time_step_event_in, sim_node_particle_time_step_event_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc b/source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc
new file mode 100644
index 00000000000..8696dbe340c
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc
@@ -0,0 +1,57 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_set_particle_attribute_in[] = {
+ {SOCK_STRING, N_("Name")},
+ {SOCK_FLOAT, N_("Float"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_INT, N_("Int"), 0, 0, 0, 0, -10000, 10000},
+ {SOCK_BOOLEAN, N_("Boolean")},
+ {SOCK_VECTOR, N_("Vector")},
+ {SOCK_RGBA, N_("Color")},
+ {SOCK_OBJECT, N_("Object")},
+ {SOCK_IMAGE, N_("Image")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_set_particle_attribute_out[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static void sim_node_set_particle_attribute_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ int index = 0;
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ if (index >= 1) {
+ nodeSetSocketAvailability(sock, sock->type == node->custom1);
+ }
+ index++;
+ }
+}
+
+void register_node_type_sim_set_particle_attribute()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_SET_PARTICLE_ATTRIBUTE, "Set Particle Attribute", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_set_particle_attribute_in, sim_node_set_particle_attribute_out);
+ node_type_update(&ntype, sim_node_set_particle_attribute_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_simulation_time.cc b/source/blender/nodes/simulation/nodes/node_sim_simulation_time.cc
new file mode 100644
index 00000000000..40e1c43fb69
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_simulation_time.cc
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_time_out[] = {
+ {SOCK_FLOAT, N_("Time")},
+ {-1, ""},
+};
+
+void register_node_type_sim_time()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_TIME, "Time", 0, 0);
+ node_type_socket_templates(&ntype, nullptr, sim_node_time_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 31f67cb1ffa..b3d595cc69b 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -282,7 +282,7 @@ int ntreeTexExecTree(bNodeTree *nodes,
float dyt[3],
int osatex,
const short thread,
- Tex *UNUSED(tex),
+ const Tex *UNUSED(tex),
short which_output,
int cfra,
int preview,
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 726599ff06e..50ae05694eb 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -33,7 +33,7 @@
#include "BLI_math_base.h"
#include "BLI_string.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "bpy_rna_driver.h" /* for pyrna_driver_get_variable_value */
diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c
index a8d8252b231..9240e34bbab 100644
--- a/source/blender/python/intern/bpy_rna_driver.c
+++ b/source/blender/python/intern/bpy_rna_driver.c
@@ -26,7 +26,7 @@
#include "BLI_utildefines.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "RNA_access.h"
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 6ea0dd52ed7..ace7480ee81 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -930,7 +930,7 @@ PyDoc_STRVAR(Vector_dot_doc,
" :arg other: The other vector to perform the dot product with.\n"
" :type other: :class:`Vector`\n"
" :return: The dot product.\n"
- " :rtype: :class:`Vector`\n");
+ " :rtype: float\n");
static PyObject *Vector_dot(VectorObject *self, PyObject *value)
{
float *tvec;
diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h
index bca3b749192..bdf81354b8d 100644
--- a/source/blender/render/extern/include/RE_render_ext.h
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -33,18 +33,16 @@ struct ImagePool;
struct MTex;
/* render_texture.c */
-/* used by particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */
-int externtex(const struct MTex *mtex,
- const float vec[3],
- float *tin,
- float *tr,
- float *tg,
- float *tb,
- float *ta,
- const int thread,
- struct ImagePool *pool,
- const bool skip_load_image,
- const bool texnode_preview);
+bool RE_texture_evaluate(const struct MTex *mtex,
+ const float vec[3],
+ const int thread,
+ struct ImagePool *pool,
+ const bool skip_load_image,
+ const bool texnode_preview,
+ /* Return arguments. */
+ float *r_intensity,
+ float r_rgba[4]) ATTR_NONNULL(1, 2, 7, 8);
+
void texture_rgb_blend(
float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype);
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype);
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index f7901ebb7d0..77a482f8546 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -2514,7 +2514,7 @@ void RE_RenderAnim(Render *re,
{
float ctime = BKE_scene_frame_get(scene);
AnimData *adt = BKE_animdata_from_id(&scene->id);
- BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, ADT_RECALC_ALL, false);
+ BKE_animsys_evaluate_animdata(&scene->id, adt, ctime, ADT_RECALC_ALL, false);
}
render_update_depsgraph(re);
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index eabba94ef29..ee484924bf9 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -79,7 +79,7 @@ void RE_texture_rng_exit(void)
/* ------------------------------------------------------------------------- */
/* this allows colorbanded textures to control normals as well */
-static void tex_normal_derivate(Tex *tex, TexResult *texres)
+static void tex_normal_derivate(const Tex *tex, TexResult *texres)
{
if (tex->flag & TEX_COLORBAND) {
float col[4];
@@ -106,7 +106,7 @@ static void tex_normal_derivate(Tex *tex, TexResult *texres)
texres->nor[2] = texres->tin - texres->nor[2];
}
-static int blend(Tex *tex, const float texvec[3], TexResult *texres)
+static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
{
float x, y, t;
@@ -170,7 +170,7 @@ static int blend(Tex *tex, const float texvec[3], TexResult *texres)
/* newnoise: all noisebased types now have different noisebases to choose from */
-static int clouds(Tex *tex, const float texvec[3], TexResult *texres)
+static int clouds(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
@@ -271,7 +271,7 @@ static float tex_tri(float a)
}
/* computes basic wood intensity value at x,y,z */
-static float wood_int(Tex *tex, float x, float y, float z)
+static float wood_int(const Tex *tex, float x, float y, float z)
{
float wi = 0;
/* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */
@@ -308,7 +308,7 @@ static float wood_int(Tex *tex, float x, float y, float z)
return wi;
}
-static int wood(Tex *tex, const float texvec[3], TexResult *texres)
+static int wood(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
@@ -329,7 +329,7 @@ static int wood(Tex *tex, const float texvec[3], TexResult *texres)
}
/* computes basic marble intensity at x,y,z */
-static float marble_int(Tex *tex, float x, float y, float z)
+static float marble_int(const Tex *tex, float x, float y, float z)
{
float n, mi;
short wf = tex->noisebasis2; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */
@@ -367,7 +367,7 @@ static float marble_int(Tex *tex, float x, float y, float z)
return mi;
}
-static int marble(Tex *tex, const float texvec[3], TexResult *texres)
+static int marble(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
@@ -391,7 +391,7 @@ static int marble(Tex *tex, const float texvec[3], TexResult *texres)
/* ------------------------------------------------------------------------- */
-static int magic(Tex *tex, const float texvec[3], TexResult *texres)
+static int magic(const Tex *tex, const float texvec[3], TexResult *texres)
{
float x, y, z, turb;
int n;
@@ -467,7 +467,7 @@ static int magic(Tex *tex, const float texvec[3], TexResult *texres)
/* ------------------------------------------------------------------------- */
/* newnoise: stucci also modified to use different noisebasis */
-static int stucci(Tex *tex, const float texvec[3], TexResult *texres)
+static int stucci(const Tex *tex, const float texvec[3], TexResult *texres)
{
float nor[3], b2, ofs;
int retval = TEX_INT;
@@ -533,7 +533,7 @@ static int stucci(Tex *tex, const float texvec[3], TexResult *texres)
/* ------------------------------------------------------------------------- */
/* newnoise: musgrave terrain noise types */
-static float mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *texres)
+static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
float (*mgravefunc)(float, float, float, float, float, float, int);
@@ -588,7 +588,7 @@ static float mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *tex
return rv;
}
-static float mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult *texres)
+static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
float (*mgravefunc)(float, float, float, float, float, float, float, float, int);
@@ -651,7 +651,7 @@ static float mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult *
return rv;
}
-static float mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres)
+static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
@@ -702,7 +702,7 @@ static float mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres)
return rv;
}
-static float mg_distNoiseTex(Tex *tex, const float texvec[3], TexResult *texres)
+static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
@@ -747,7 +747,7 @@ static float mg_distNoiseTex(Tex *tex, const float texvec[3], TexResult *texres)
* probably the slowest, especially with minkovsky, bumpmapping, could be done another way.
*/
-static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
+static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
float da[4], pa[12]; /* distance and point coordinate arrays of 4 nearest neighbors */
@@ -761,8 +761,7 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
}
voronoi(texvec[0], texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
- texres->tin = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] +
- tex->vn_w4 * da[3]);
+ texres->tin = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
if (tex->vn_coltype) {
float ca[3]; /* cell color */
@@ -809,14 +808,11 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
/* calculate bumpnormal */
voronoi(texvec[0] + offs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[0] = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] +
- tex->vn_w4 * da[3]);
+ texres->nor[0] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
voronoi(texvec[0], texvec[1] + offs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[1] = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] +
- tex->vn_w4 * da[3]);
+ texres->nor[1] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
voronoi(texvec[0], texvec[1], texvec[2] + offs, da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[2] = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] +
- tex->vn_w4 * da[3]);
+ texres->nor[2] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
tex_normal_derivate(tex, texres);
rv |= TEX_NOR;
@@ -835,7 +831,7 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
/* ------------------------------------------------------------------------- */
-static int texnoise(Tex *tex, TexResult *texres, int thread)
+static int texnoise(const Tex *tex, TexResult *texres, int thread)
{
float div = 3.0;
int val, ran, loop, shift = 29;
@@ -1724,17 +1720,20 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
/* ------------------------------------------------------------------------- */
-int externtex(const MTex *mtex,
- const float vec[3],
- float *tin,
- float *tr,
- float *tg,
- float *tb,
- float *ta,
- const int thread,
- struct ImagePool *pool,
- const bool skip_load_image,
- const bool texnode_preview)
+/**
+ * \param pool: Thread pool, may be NULL.
+ *
+ * \return True if the texture has color, otherwise false.
+ */
+bool RE_texture_evaluate(const MTex *mtex,
+ const float vec[3],
+ const int thread,
+ struct ImagePool *pool,
+ const bool skip_load_image,
+ const bool texnode_preview,
+ /* Return arguments. */
+ float *r_intensity,
+ float r_rgba[4])
{
Tex *tex;
TexResult texr;
@@ -1796,11 +1795,11 @@ int externtex(const MTex *mtex,
texr.tb = mtex->b;
}
- *tin = texr.tin;
- *tr = texr.tr;
- *tg = texr.tg;
- *tb = texr.tb;
- *ta = texr.ta;
+ *r_intensity = texr.tin;
+ r_rgba[0] = texr.tr;
+ r_rgba[1] = texr.tg;
+ r_rgba[2] = texr.tb;
+ r_rgba[3] = texr.ta;
return (rgb != 0);
}
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 90ff7bb8f85..22fd55cd49a 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -153,8 +153,8 @@ endif()
if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
-elseif(WITH_X11)
- add_definitions(-DWITH_X11)
+elseif(WITH_GHOST_X11)
+ add_definitions(-DWITH_GHOST_X11)
endif()
if(WITH_PYTHON)
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 2f540262a66..21a6088bfe9 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -617,7 +617,7 @@ int WM_gesture_lasso_modal(struct bContext *C, struct wmOperator *op, const stru
void WM_gesture_lasso_cancel(struct bContext *C, struct wmOperator *op);
const int (*WM_gesture_lasso_path_to_array(struct bContext *C,
struct wmOperator *op,
- int *mcords_tot))[2];
+ int *mcoords_len))[2];
int WM_gesture_straightline_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
@@ -872,6 +872,7 @@ void WM_generic_user_data_free(struct wmGenericUserData *user_data);
bool WM_xr_session_exists(const wmXrData *xr);
bool WM_xr_session_is_ready(const wmXrData *xr);
struct wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr);
+void WM_xr_session_base_pose_reset(wmXrData *xr);
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3]);
bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4]);
bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr,
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 8b8c1b90dc9..560581a56e2 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -3170,9 +3170,9 @@ void wm_event_do_handlers(bContext *C)
}
if (is_playing_sound == 0) {
- const float time = BKE_sound_sync_scene(scene_eval);
+ const double time = BKE_sound_sync_scene(scene_eval);
if (isfinite(time)) {
- int ncfra = time * (float)FPS + 0.5f;
+ int ncfra = time * FPS + 0.5;
if (ncfra != scene->r.cfra) {
scene->r.cfra = ncfra;
ED_update_for_newframe(CTX_data_main(C), depsgraph);
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 71ae44297e7..9aa401722b7 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -320,24 +320,24 @@ static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data)
static void draw_filled_lasso(wmGesture *gt)
{
const short *lasso = (short *)gt->customdata;
- const int tot = gt->points;
- int(*moves)[2] = MEM_mallocN(sizeof(*moves) * (tot + 1), __func__);
+ const int mcoords_len = gt->points;
+ int(*mcoords)[2] = MEM_mallocN(sizeof(*mcoords) * (mcoords_len + 1), __func__);
int i;
rcti rect;
float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
- for (i = 0; i < tot; i++, lasso += 2) {
- moves[i][0] = lasso[0];
- moves[i][1] = lasso[1];
+ for (i = 0; i < mcoords_len; i++, lasso += 2) {
+ mcoords[i][0] = lasso[0];
+ mcoords[i][1] = lasso[1];
}
- BLI_lasso_boundbox(&rect, (const int(*)[2])moves, tot);
+ BLI_lasso_boundbox(&rect, (const int(*)[2])mcoords, mcoords_len);
BLI_rcti_translate(&rect, gt->winrct.xmin, gt->winrct.ymin);
BLI_rcti_isect(&gt->winrct, &rect, &rect);
BLI_rcti_translate(&rect, -gt->winrct.xmin, -gt->winrct.ymin);
- /* highly unlikely this will fail, but could crash if (tot == 0) */
+ /* Highly unlikely this will fail, but could crash if (mcoords_len == 0). */
if (BLI_rcti_is_empty(&rect) == false) {
const int w = BLI_rcti_size_x(&rect);
const int h = BLI_rcti_size_y(&rect);
@@ -348,8 +348,8 @@ static void draw_filled_lasso(wmGesture *gt)
rect.ymin,
rect.xmax,
rect.ymax,
- (const int(*)[2])moves,
- tot,
+ (const int(*)[2])mcoords,
+ mcoords_len,
draw_filled_lasso_px_cb,
&lasso_fill_data);
@@ -390,7 +390,7 @@ static void draw_filled_lasso(wmGesture *gt)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
- MEM_freeN(moves);
+ MEM_freeN(mcoords);
}
static void wm_gesture_draw_lasso(wmGesture *gt, bool filled)
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index 11beb7d2fd5..9fb368a02b4 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -718,10 +718,10 @@ void WM_gesture_lines_cancel(bContext *C, wmOperator *op)
*/
const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C),
wmOperator *op,
- int *mcords_tot))[2]
+ int *r_mcoords_len))[2]
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "path");
- int(*mcords)[2] = NULL;
+ int(*mcoords)[2] = NULL;
BLI_assert(prop != NULL);
if (prop) {
@@ -729,26 +729,26 @@ const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C),
if (len) {
int i = 0;
- mcords = MEM_mallocN(sizeof(int) * 2 * len, __func__);
+ mcoords = MEM_mallocN(sizeof(int[2]) * len, __func__);
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
float loc[2];
RNA_float_get_array(&itemptr, "loc", loc);
- mcords[i][0] = (int)loc[0];
- mcords[i][1] = (int)loc[1];
+ mcoords[i][0] = (int)loc[0];
+ mcoords[i][1] = (int)loc[1];
i++;
}
RNA_PROP_END;
}
- *mcords_tot = len;
+ *r_mcoords_len = len;
}
else {
- *mcords_tot = 0;
+ *r_mcoords_len = 0;
}
/* cast for 'const' */
- return (const int(*)[2])mcords;
+ return mcoords;
}
#if 0
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 17d697840a0..a93d4c7bf37 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -44,6 +44,7 @@
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_timer.h"
#include "BLI_utildefines.h"
@@ -198,7 +199,7 @@ void WM_init_opengl(Main *bmain)
opengl_is_init = true;
}
-static void sound_jack_sync_callback(Main *bmain, int mode, float time)
+static void sound_jack_sync_callback(Main *bmain, int mode, double time)
{
/* Ugly: Blender doesn't like it when the animation is played back during rendering. */
if (G.is_rendering) {
@@ -648,6 +649,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
DNA_sdna_current_free();
BLI_threadapi_exit();
+ BLI_task_scheduler_exit();
/* No need to call this early, rather do it late so that other
* pieces of Blender using sound may exit cleanly, see also T50676. */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index a7578291a21..96b2fcf92e7 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1349,17 +1349,8 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *region, void *arg_op)
}
uiLayout *col = uiLayoutColumn(layout, false);
-
- if (op->type->flag & OPTYPE_MACRO) {
- for (op = op->macro.first; op; op = op->next) {
- uiTemplateOperatorPropertyButs(
- C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
- }
- }
- else {
- uiTemplateOperatorPropertyButs(
- C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
- }
+ uiTemplateOperatorPropertyButs(
+ C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL);
@@ -1794,13 +1785,12 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *eve
}
}
- PropertyRNA *prop = op->type->prop;
int search_type;
- if (RNA_property_is_set(op->ptr, prop)) {
- search_type = RNA_property_enum_get(op->ptr, prop);
+ if (STREQ(op->type->idname, "WM_OT_search_menu")) {
+ search_type = SEARCH_TYPE_MENU;
}
else {
- search_type = U.experimental.use_menu_search ? SEARCH_TYPE_MENU : SEARCH_TYPE_OPERATOR;
+ search_type = SEARCH_TYPE_OPERATOR;
}
static struct SearchPopupInit_Data data;
@@ -1818,20 +1808,22 @@ static void WM_OT_search_menu(wmOperatorType *ot)
{
ot->name = "Search Menu";
ot->idname = "WM_OT_search_menu";
- ot->description = "Pop-up a search menu over all available operators in current context";
+ ot->description = "Pop-up a search over all menus in the current context";
ot->invoke = wm_search_menu_invoke;
ot->exec = wm_search_menu_exec;
ot->poll = WM_operator_winactive;
+}
- static const EnumPropertyItem search_type_items[] = {
- {SEARCH_TYPE_OPERATOR, "OPERATOR", 0, "Operator", "Search all operators"},
- {SEARCH_TYPE_MENU, "MENU", 0, "Menu", "Search active menu items"},
- {0, NULL, 0, NULL, NULL},
- };
+static void WM_OT_search_operator(wmOperatorType *ot)
+{
+ ot->name = "Search Operator";
+ ot->idname = "WM_OT_search_operator";
+ ot->description = "Pop-up a search over all available operators in current context";
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", search_type_items, SEARCH_TYPE_OPERATOR, "Type", "");
+ ot->invoke = wm_search_menu_invoke;
+ ot->exec = wm_search_menu_exec;
+ ot->poll = WM_operator_winactive;
}
static int wm_call_menu_exec(bContext *C, wmOperator *op)
@@ -3806,6 +3798,7 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_operator_defaults);
WM_operatortype_append(WM_OT_splash);
WM_operatortype_append(WM_OT_search_menu);
+ WM_operatortype_append(WM_OT_search_operator);
WM_operatortype_append(WM_OT_call_menu);
WM_operatortype_append(WM_OT_call_menu_pie);
WM_operatortype_append(WM_OT_call_panel);
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 84f099b0dbc..948e8d9fb74 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -317,7 +317,13 @@ static void playanim_toscreen(
GPU_blend(true);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- imm_draw_box_checker_2d(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
+ imm_draw_box_checker_2d_ex(offs_x,
+ offs_y,
+ offs_x + span_x,
+ offs_y + span_y,
+ (const float[4]){0.15, 0.15, 0.15, 1.0},
+ (const float[4]){0.20, 0.20, 0.20, 1.0},
+ 8);
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 2a5fdc0ab74..080c2ee26c2 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -769,19 +769,6 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
* in practice the window manager will likely move to the correct monitor */
wm_init_state.start_x = 0;
wm_init_state.start_y = 0;
-
-#ifdef WITH_X11 /* X11 */
- /* X11, don't start maximized because we can't figure out the dimensions
- * of a single display yet if there are multiple, due to lack of Xinerama
- * handling in GHOST. */
- wm_init_state.size_x = min_ii(wm_init_state.size_x, WM_WIN_INIT_SIZE_X);
- wm_init_state.size_y = min_ii(wm_init_state.size_y, WM_WIN_INIT_SIZE_Y);
- /* pad */
- wm_init_state.start_x = WM_WIN_INIT_PAD;
- wm_init_state.start_y = WM_WIN_INIT_PAD;
- wm_init_state.size_x -= WM_WIN_INIT_PAD * 2;
- wm_init_state.size_y -= WM_WIN_INIT_PAD * 2;
-#endif
}
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index ce9d79b8e59..45cfe1431d7 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -82,11 +82,4 @@ int wm_window_new_main_exec(bContext *C, struct wmOperator *op);
void wm_test_autorun_warning(bContext *C);
-/* Initial (unmaximized) size to start with for
- * systems that can't find it for themselves (X11).
- * Clamped by real desktop limits */
-#define WM_WIN_INIT_SIZE_X 1800
-#define WM_WIN_INIT_SIZE_Y 1000
-#define WM_WIN_INIT_PAD 40
-
#endif /* __WM_WINDOW_H__ */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
index b53ae45a29f..9b7e9a15948 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -34,11 +34,16 @@ typedef struct wmXrSessionState {
float viewer_viewmat[4][4];
float focal_len;
+ /** Copy of XrSessionSettings.base_pose_ data to detect changes that need
+ * resetting to base pose. */
+ char prev_base_pose_type; /* eXRSessionBasePoseType */
+ Object *prev_base_pose_object;
/** Copy of XrSessionSettings.flag created on the last draw call, stored to detect changes. */
int prev_settings_flag;
/** Copy of wmXrDrawData.eye_position_ofs. */
float prev_eye_position_ofs[3];
+ bool force_reset_to_base_pose;
bool is_view_data_set;
} wmXrSessionState;
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index dc228d1b18b..e9ff38c5a92 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -95,6 +95,11 @@ bool WM_xr_session_exists(const wmXrData *xr)
return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started;
}
+void WM_xr_session_base_pose_reset(wmXrData *xr)
+{
+ xr->runtime->session_state.force_reset_to_base_pose = true;
+}
+
/**
* Check if the session is running, according to the OpenXR definition.
*/
@@ -154,6 +159,17 @@ static void wm_xr_session_draw_data_populate(wmXrData *xr_data,
wm_xr_session_base_pose_calc(r_draw_data->scene, settings, &r_draw_data->base_pose);
}
+static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionState *state,
+ const XrSessionSettings *settings)
+{
+ if (state->force_reset_to_base_pose) {
+ return true;
+ }
+ return ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) &&
+ ((state->prev_base_pose_type != settings->base_pose_type) ||
+ (state->prev_base_pose_object != settings->base_pose_object));
+}
+
void wm_xr_session_draw_data_update(const wmXrSessionState *state,
const XrSessionSettings *settings,
const GHOST_XrDrawViewInfo *draw_view,
@@ -166,7 +182,8 @@ void wm_xr_session_draw_data_update(const wmXrSessionState *state,
/* Set the eye position offset, it's used to offset the base pose when changing positional
* tracking. */
- if (!state->is_view_data_set) {
+ if (!state->is_view_data_set ||
+ wm_xr_session_draw_data_needs_reset_to_base_pose(state, settings)) {
/* Always use the exact base pose with no offset when starting the session. */
copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
}
@@ -223,6 +240,8 @@ void wm_xr_session_state_update(const XrSessionSettings *settings,
copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
state->prev_settings_flag = settings->flag;
+ state->prev_base_pose_type = settings->base_pose_type;
+ state->prev_base_pose_object = settings->base_pose_object;
state->is_view_data_set = true;
}
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 4b51f9738b3..b3e83b1412f 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -687,6 +687,17 @@ elseif(WIN32)
)
endif()
+ if(WITH_WINDOWS_PDB)
+ if(WITH_WINDOWS_STRIPPED_PDB)
+ # Icky hack for older cmake from https://stackoverflow.com/a/21198501
+ # $<CONFIG> will work in newer cmake but the version currently (3.12)
+ # on the buildbot does not support this endavour.
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}/blender_public.pdb DESTINATION . RENAME blender.pdb)
+ else()
+ install(FILES $<TARGET_PDB_FILE:blender> DESTINATION . RENAME blender.pdb)
+ endif()
+ endif()
+
if(WITH_PYTHON)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
@@ -803,7 +814,20 @@ elseif(WIN32)
DESTINATION "."
)
endif()
-
+ if(WITH_TBB)
+ install(
+ FILES
+ ${LIBDIR}/tbb/lib/tbb.dll
+ DESTINATION "."
+ CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
+ )
+ install(
+ FILES
+ ${LIBDIR}/tbb/lib/debug/tbb_debug.dll
+ DESTINATION "."
+ CONFIGURATIONS Debug
+ )
+ endif()
if(WITH_TBB_MALLOC_PROXY)
install(
FILES
@@ -1085,6 +1109,20 @@ endif()
# the use of vcpkg
if(WIN32)
set_target_properties(blender PROPERTIES VS_GLOBAL_VcpkgEnabled "false")
+ set_target_properties(blender PROPERTIES
+ PDB_NAME "blender_private"
+ PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
+ if (WITH_WINDOWS_PDB AND WITH_WINDOWS_STRIPPED_PDB)
+ # This is slightly messy, but single target generators like ninja will not have the
+ # CMAKE_CFG_INTDIR variable and multitarget generators like msbuild will not have
+ # CMAKE_BUILD_TYPE. This can be simplified by target_link_options and the $<CONFIG>
+ # generator expression in newer cmake (2.13+) but until that time this fill have suffice.
+ if(CMAKE_BUILD_TYPE)
+ set_property(TARGET blender APPEND PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/blender_public.pdb")
+ else()
+ set_property(TARGET blender APPEND PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/blender_public.pdb")
+ endif()
+ endif()
endif()
# -----------------------------------------------------------------------------
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 6c4af7be95e..ea64184c826 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -43,6 +43,7 @@
#include "BLI_args.h"
#include "BLI_string.h"
#include "BLI_system.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -401,6 +402,9 @@ int main(int argc,
G.factory_startup = true;
#endif
+ /* After parsing number of threads argument. */
+ BLI_task_scheduler_init();
+
#ifdef WITH_FFMPEG
IMB_ffmpeg_init();
#endif
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
index 7f7a03f0465..dbf947a86fd 100644
--- a/source/creator/creator_signals.c
+++ b/source/creator/creator_signals.c
@@ -190,97 +190,25 @@ static void sig_handle_crash(int signum)
}
# ifdef WIN32
-LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
+extern LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
{
- switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
- case EXCEPTION_ACCESS_VIOLATION:
- fputs("Error : EXCEPTION_ACCESS_VIOLATION\n", stderr);
- break;
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- fputs("Error : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
- break;
- case EXCEPTION_BREAKPOINT:
- fputs("Error : EXCEPTION_BREAKPOINT\n", stderr);
- break;
- case EXCEPTION_DATATYPE_MISALIGNMENT:
- fputs("Error : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
- break;
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- fputs("Error : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
- break;
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- fputs("Error : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
- break;
- case EXCEPTION_FLT_INEXACT_RESULT:
- fputs("Error : EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
- break;
- case EXCEPTION_FLT_INVALID_OPERATION:
- fputs("Error : EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
- break;
- case EXCEPTION_FLT_OVERFLOW:
- fputs("Error : EXCEPTION_FLT_OVERFLOW\n", stderr);
- break;
- case EXCEPTION_FLT_STACK_CHECK:
- fputs("Error : EXCEPTION_FLT_STACK_CHECK\n", stderr);
- break;
- case EXCEPTION_FLT_UNDERFLOW:
- fputs("Error : EXCEPTION_FLT_UNDERFLOW\n", stderr);
- break;
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- fputs("Error : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
- break;
- case EXCEPTION_IN_PAGE_ERROR:
- fputs("Error : EXCEPTION_IN_PAGE_ERROR\n", stderr);
- break;
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- fputs("Error : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
- break;
- case EXCEPTION_INT_OVERFLOW:
- fputs("Error : EXCEPTION_INT_OVERFLOW\n", stderr);
- break;
- case EXCEPTION_INVALID_DISPOSITION:
- fputs("Error : EXCEPTION_INVALID_DISPOSITION\n", stderr);
- break;
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- fputs("Error : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
- break;
- case EXCEPTION_PRIV_INSTRUCTION:
- fputs("Error : EXCEPTION_PRIV_INSTRUCTION\n", stderr);
- break;
- case EXCEPTION_SINGLE_STEP:
- fputs("Error : EXCEPTION_SINGLE_STEP\n", stderr);
- break;
- case EXCEPTION_STACK_OVERFLOW:
- fputs("Error : EXCEPTION_STACK_OVERFLOW\n", stderr);
- break;
- default:
- fputs("Error : Unrecognized Exception\n", stderr);
- break;
- }
-
- fflush(stderr);
-
- /* If this is a stack overflow then we can't walk the stack, so just show
+ /* If this is a stack overflow then we can't walk the stack, so just try to show
* where the error happened */
- if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
HMODULE mod;
CHAR modulename[MAX_PATH];
LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress;
-
+ fprintf(stderr, "Error : EXCEPTION_STACK_OVERFLOW\n");
fprintf(stderr, "Address : 0x%p\n", address);
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) {
if (GetModuleFileName(mod, modulename, MAX_PATH)) {
fprintf(stderr, "Module : %s\n", modulename);
}
}
-
- fflush(stderr);
-
-# ifdef NDEBUG
- TerminateProcess(GetCurrentProcess(), SIGSEGV);
-# else
+ }
+ else {
+ BLI_windows_handle_exception(ExceptionInfo);
sig_handle_crash(SIGSEGV);
-# endif
}
return EXCEPTION_EXECUTE_HANDLER;
diff --git a/source/tools b/source/tools
-Subproject 35dd27ded664b1068e773c27988ee221f3ce39d
+Subproject 8a36c2833db48ed78c436ee19534ce5cf3b2eee
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 966572b23e7..80d749c7040 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -14,15 +14,27 @@ endif()
# Path to Blender and Python executables for all platforms.
if(MSVC)
set(TEST_BLENDER_EXE ${TEST_INSTALL_DIR}/blender.exe)
- set(TEST_PYTHON_EXE "${TEST_INSTALL_DIR}/${BLENDER_VERSION_MAJOR}.${BLENDER_VERSION_MINOR}/python/bin/python$<$<CONFIG:Debug>:_d>")
+ set(_default_test_python_exe "${TEST_INSTALL_DIR}/${BLENDER_VERSION_MAJOR}.${BLENDER_VERSION_MINOR}/python/bin/python$<$<CONFIG:Debug>:_d>")
elseif(APPLE)
set(TEST_BLENDER_EXE ${TEST_INSTALL_DIR}/Blender.app/Contents/MacOS/Blender)
- set(TEST_PYTHON_EXE)
+ set(_default_test_python_exe ${PYTHON_EXECUTABLE})
else()
set(TEST_BLENDER_EXE ${TEST_INSTALL_DIR}/blender)
- set(TEST_PYTHON_EXE)
+ set(_default_test_python_exe ${PYTHON_EXECUTABLE})
endif()
+# The installation directory's Python is the best one to use. However, it can only be there after the install step,
+# which means that Python will never be there on a fresh system. To suit different needs, the user can pass
+# -DTEST_PYTHON_EXE=/path/to/python to CMake.
+if (NOT TEST_PYTHON_EXE)
+ set(TEST_PYTHON_EXE ${_default_test_python_exe})
+ message(STATUS "Tests: Using Python executable: ${TEST_PYTHON_EXE}")
+elseif(NOT EXISTS ${TEST_PYTHON_EXE})
+ message(FATAL_ERROR "Tests: TEST_PYTHON_EXE ${TEST_PYTHON_EXE} does not exist")
+endif()
+unset(_default_test_python_exe)
+
+
# For testing with Valgrind
# set(TEST_BLENDER_EXE valgrind --track-origins=yes --error-limit=no ${TEST_BLENDER_EXE})
diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt
index bcf77fb6de7..c02bad471ff 100644
--- a/tests/gtests/CMakeLists.txt
+++ b/tests/gtests/CMakeLists.txt
@@ -12,6 +12,7 @@ if(WITH_GTESTS)
remove_strict_flags()
add_subdirectory(testing)
+ add_subdirectory(blenkernel)
add_subdirectory(blenlib)
add_subdirectory(blenloader)
add_subdirectory(guardedalloc)
diff --git a/tests/gtests/blenkernel/BKE_armature_test.cc b/tests/gtests/blenkernel/BKE_armature_test.cc
new file mode 100644
index 00000000000..ed6045081d4
--- /dev/null
+++ b/tests/gtests/blenkernel/BKE_armature_test.cc
@@ -0,0 +1,89 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation
+ * All rights reserved.
+ */
+
+#include "BKE_armature.h"
+
+#include "BLI_math.h"
+
+#include "testing/testing.h"
+
+static const float FLOAT_EPSILON = 1.2e-7;
+
+TEST(mat3_vec_to_roll, UnitMatrix)
+{
+ float unit_matrix[3][3];
+ float roll;
+
+ unit_m3(unit_matrix);
+
+ // Any vector with a unit matrix should return zero roll.
+ mat3_vec_to_roll(unit_matrix, unit_matrix[0], &roll);
+ EXPECT_FLOAT_EQ(0.0f, roll);
+
+ mat3_vec_to_roll(unit_matrix, unit_matrix[1], &roll);
+ EXPECT_FLOAT_EQ(0.0f, roll);
+
+ mat3_vec_to_roll(unit_matrix, unit_matrix[2], &roll);
+ EXPECT_FLOAT_EQ(0.0f, roll);
+
+ {
+ // Non-unit vector.
+ float vector[3] = {1.0f, 1.0f, 1.0f};
+ mat3_vec_to_roll(unit_matrix, vector, &roll);
+ EXPECT_NEAR(0.0f, roll, FLOAT_EPSILON);
+
+ // Normalized version of the above vector.
+ normalize_v3(vector);
+ mat3_vec_to_roll(unit_matrix, vector, &roll);
+ EXPECT_NEAR(0.0f, roll, FLOAT_EPSILON);
+ }
+}
+
+TEST(mat3_vec_to_roll, Rotationmatrix)
+{
+ float rotation_matrix[3][3];
+ float roll;
+
+ const float rot_around_x[3] = {1.234f, 0.0f, 0.0f};
+ eul_to_mat3(rotation_matrix, rot_around_x);
+
+ {
+ const float unit_axis_x[3] = {1.0f, 0.0f, 0.0f};
+ mat3_vec_to_roll(rotation_matrix, unit_axis_x, &roll);
+ EXPECT_NEAR(1.234f, roll, FLOAT_EPSILON);
+ }
+
+ {
+ const float unit_axis_y[3] = {0.0f, 1.0f, 0.0f};
+ mat3_vec_to_roll(rotation_matrix, unit_axis_y, &roll);
+ EXPECT_NEAR(0, roll, FLOAT_EPSILON);
+ }
+
+ {
+ const float unit_axis_z[3] = {0.0f, 0.0f, 1.0f};
+ mat3_vec_to_roll(rotation_matrix, unit_axis_z, &roll);
+ EXPECT_NEAR(0, roll, FLOAT_EPSILON);
+ }
+
+ {
+ const float between_x_and_y[3] = {1.0f, 1.0f, 0.0f};
+ mat3_vec_to_roll(rotation_matrix, between_x_and_y, &roll);
+ EXPECT_NEAR(0.57158958f, roll, FLOAT_EPSILON);
+ }
+}
diff --git a/tests/gtests/blenkernel/BKE_fcurve_test.cc b/tests/gtests/blenkernel/BKE_fcurve_test.cc
new file mode 100644
index 00000000000..d28c5075bd8
--- /dev/null
+++ b/tests/gtests/blenkernel/BKE_fcurve_test.cc
@@ -0,0 +1,211 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 by Blender Foundation.
+ */
+#include "testing/testing.h"
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BKE_fcurve.h"
+
+#include "ED_keyframing.h"
+
+#include "DNA_anim_types.h"
+}
+
+// Epsilon for floating point comparisons.
+static const float EPSILON = 1e-7f;
+
+TEST(evaluate_fcurve, EmptyFCurve)
+{
+ FCurve *fcu = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), "FCurve"));
+ EXPECT_EQ(evaluate_fcurve(fcu, 47.0f), 0.0f);
+ free_fcurve(fcu);
+}
+
+TEST(evaluate_fcurve, OnKeys)
+{
+ FCurve *fcu = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), "FCurve"));
+
+ insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
+ insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
+ insert_vert_fcurve(fcu, 3.0f, 19.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
+
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.0f), 7.0f, EPSILON); // hits 'on or before first' function
+ EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f), 13.0f, EPSILON); // hits 'between' function
+ EXPECT_NEAR(evaluate_fcurve(fcu, 3.0f), 19.0f, EPSILON); // hits 'on or after last' function
+
+ /* Also test within a specific time epsilon of the keys, as this was an issue in T39207.
+ * This epsilon is just slightly smaller than the epsilon given to binarysearch_bezt_index_ex()
+ * in fcurve_eval_between_keyframes(), so it should hit the "exact" code path. */
+ float time_epsilon = 0.00008f;
+ EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f - time_epsilon), 13.0f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f + time_epsilon), 13.0f, EPSILON);
+
+ free_fcurve(fcu);
+}
+
+TEST(evaluate_fcurve, InterpolationConstant)
+{
+ FCurve *fcu = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), "FCurve"));
+
+ EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
+ EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
+
+ fcu->bezt[0].ipo = BEZT_IPO_CONST;
+ fcu->bezt[1].ipo = BEZT_IPO_CONST;
+
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.0f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 7.0f, EPSILON);
+
+ free_fcurve(fcu);
+}
+
+TEST(evaluate_fcurve, InterpolationLinear)
+{
+ FCurve *fcu = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), "FCurve"));
+
+ EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
+ EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
+
+ fcu->bezt[0].ipo = BEZT_IPO_LIN;
+ fcu->bezt[1].ipo = BEZT_IPO_LIN;
+
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 8.5f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.5f, EPSILON);
+
+ free_fcurve(fcu);
+}
+
+TEST(evaluate_fcurve, InterpolationBezier)
+{
+ FCurve *fcu = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), "FCurve"));
+
+ EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
+ EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
+
+ EXPECT_EQ(fcu->bezt[0].ipo, BEZT_IPO_BEZ);
+ EXPECT_EQ(fcu->bezt[1].ipo, BEZT_IPO_BEZ);
+
+ // Test with default handles.
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.8297067f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 12.170294f, EPSILON);
+
+ // Test with modified handles.
+ fcu->bezt[0].vec[0][0] = 0.71855f; // left handle X
+ fcu->bezt[0].vec[0][1] = 6.22482f; // left handle Y
+ fcu->bezt[0].vec[2][0] = 1.35148f; // right handle X
+ fcu->bezt[0].vec[2][1] = 7.96806f; // right handle Y
+
+ fcu->bezt[1].vec[0][0] = 1.66667f; // left handle X
+ fcu->bezt[1].vec[0][1] = 10.4136f; // left handle Y
+ fcu->bezt[1].vec[2][0] = 2.33333f; // right handle X
+ fcu->bezt[1].vec[2][1] = 15.5864f; // right handle Y
+
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.945497f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 9.3495407f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.088551f, EPSILON);
+
+ free_fcurve(fcu);
+}
+
+TEST(evaluate_fcurve, InterpolationBounce)
+{
+ FCurve *fcu = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), "FCurve"));
+
+ EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
+ EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
+
+ fcu->bezt[0].ipo = BEZT_IPO_BOUNCE;
+ fcu->bezt[1].ipo = BEZT_IPO_BOUNCE;
+
+ fcu->bezt[0].easing = BEZT_IPO_EASE_IN;
+ fcu->bezt[1].easing = BEZT_IPO_EASE_AUTO;
+
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.4f), 8.3649998f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.5f), 8.4062500f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 1.8f), 11.184999f, EPSILON);
+
+ free_fcurve(fcu);
+}
+
+TEST(evaluate_fcurve, ExtrapolationLinearKeys)
+{
+ FCurve *fcu = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), "FCurve"));
+
+ EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
+ EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
+ fcu->bezt[0].ipo = BEZT_IPO_LIN;
+ fcu->bezt[1].ipo = BEZT_IPO_LIN;
+
+ fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
+ // Before first keyframe.
+ EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 5.5f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 0.50f), 4.0f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), -8.0f, EPSILON);
+ // After last keyframe.
+ EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 17.5f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 22.0f, EPSILON);
+
+ fcu->extend = FCURVE_EXTRAPOLATE_CONSTANT;
+ // Before first keyframe.
+ EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON);
+ // After last keyframe.
+ EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON);
+
+ free_fcurve(fcu);
+}
+
+TEST(evaluate_fcurve, ExtrapolationBezierKeys)
+{
+ FCurve *fcu = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), "FCurve"));
+
+ EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
+ EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
+
+ fcu->bezt[0].vec[0][0] = 0.71855f; // left handle X
+ fcu->bezt[0].vec[0][1] = 6.22482f; // left handle Y
+ fcu->bezt[0].vec[2][0] = 1.35148f; // right handle X
+ fcu->bezt[0].vec[2][1] = 7.96806f; // right handle Y
+
+ fcu->bezt[1].vec[0][0] = 1.66667f; // left handle X
+ fcu->bezt[1].vec[0][1] = 10.4136f; // left handle Y
+ fcu->bezt[1].vec[2][0] = 2.33333f; // right handle X
+ fcu->bezt[1].vec[2][1] = 15.5864f; // right handle Y
+
+ fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
+ // Before first keyframe.
+ EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 6.3114409f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, -0.50f), 2.8686447f, EPSILON);
+ // After last keyframe.
+ EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 18.81946f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 24.63892f, EPSILON);
+
+ fcu->extend = FCURVE_EXTRAPOLATE_CONSTANT;
+ // Before first keyframe.
+ EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON);
+ // After last keyframe.
+ EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON);
+ EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON);
+
+ free_fcurve(fcu);
+}
diff --git a/intern/string/CMakeLists.txt b/tests/gtests/blenkernel/CMakeLists.txt
index 8c400f320ae..5cf4c7a27af 100644
--- a/intern/string/CMakeLists.txt
+++ b/tests/gtests/blenkernel/CMakeLists.txt
@@ -14,25 +14,31 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
-# The Original Code is Copyright (C) 2006, Blender Foundation
+# The Original Code is Copyright (C) 2020, Blender Foundation
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
set(INC
.
+ ..
+ ../../../source/blender/blenkernel
+ ../../../source/blender/blenlib
+ ../../../source/blender/editors/include
+ ../../../source/blender/makesdna
+ ../../../source/blender/makesrna
+ ../../../intern/guardedalloc
+ ../../../intern/atomic
)
-set(INC_SYS
+setup_libdirs()
+include_directories(${INC})
-)
-
-set(SRC
- intern/STR_String.cpp
+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}")
- STR_String.h
-)
-
-set(LIB
-)
+if(WITH_BUILDINFO)
+ set(BUILDINFO buildinfoobj)
+endif()
-blender_add_lib(bf_intern_string "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+BLENDER_TEST(BKE_armature "bf_blenloader;bf_blenkernel;bf_blenlib;${BUILDINFO}")
+BLENDER_TEST(BKE_fcurve "bf_blenloader;bf_blenkernel;bf_editor_animation;${BUILDINFO}")
diff --git a/tests/gtests/blenlib/BLI_array_ref_test.cc b/tests/gtests/blenlib/BLI_array_ref_test.cc
index aacd6113161..7a1f54e7458 100644
--- a/tests/gtests/blenlib/BLI_array_ref_test.cc
+++ b/tests/gtests/blenlib/BLI_array_ref_test.cc
@@ -1,5 +1,5 @@
-#include "BLI_array_ref.h"
-#include "BLI_vector.h"
+#include "BLI_array_ref.hh"
+#include "BLI_vector.hh"
#include "testing/testing.h"
using namespace BLI;
diff --git a/tests/gtests/blenlib/BLI_array_test.cc b/tests/gtests/blenlib/BLI_array_test.cc
index dd09c2d20f8..b1aa24aa808 100644
--- a/tests/gtests/blenlib/BLI_array_test.cc
+++ b/tests/gtests/blenlib/BLI_array_test.cc
@@ -1,4 +1,4 @@
-#include "BLI_array_cxx.h"
+#include "BLI_array.hh"
#include "testing/testing.h"
using namespace BLI;
diff --git a/tests/gtests/blenlib/BLI_index_range_test.cc b/tests/gtests/blenlib/BLI_index_range_test.cc
index 60da18b6baf..b12502f0d97 100644
--- a/tests/gtests/blenlib/BLI_index_range_test.cc
+++ b/tests/gtests/blenlib/BLI_index_range_test.cc
@@ -1,5 +1,5 @@
-#include "BLI_index_range.h"
-#include "BLI_vector.h"
+#include "BLI_index_range.hh"
+#include "BLI_vector.hh"
#include "testing/testing.h"
using BLI::ArrayRef;
diff --git a/tests/gtests/blenlib/BLI_linear_allocator_test.cc b/tests/gtests/blenlib/BLI_linear_allocator_test.cc
new file mode 100644
index 00000000000..0c67d1e76c9
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_linear_allocator_test.cc
@@ -0,0 +1,113 @@
+#include "BLI_linear_allocator.hh"
+#include "testing/testing.h"
+
+using namespace BLI;
+
+static bool is_aligned(void *ptr, uint alignment)
+{
+ BLI_assert(is_power_of_2_i(alignment));
+ return (POINTER_AS_UINT(ptr) & (alignment - 1)) == 0;
+}
+
+TEST(linear_allocator, AllocationAlignment)
+{
+ LinearAllocator<> allocator;
+
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 4), 4));
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 4), 4));
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 4), 4));
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 8), 8));
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 4), 4));
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 16), 16));
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 4), 4));
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 64), 64));
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 64), 64));
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 8), 8));
+ EXPECT_TRUE(is_aligned(allocator.allocate(10, 128), 128));
+}
+
+TEST(linear_allocator, PackedAllocation)
+{
+ LinearAllocator<> allocator;
+ BLI::AlignedBuffer<256, 32> buffer;
+ allocator.provide_buffer(buffer);
+
+ uintptr_t ptr1 = (uintptr_t)allocator.allocate(10, 4); /* 0 - 10 */
+ uintptr_t ptr2 = (uintptr_t)allocator.allocate(10, 4); /* 12 - 22 */
+ uintptr_t ptr3 = (uintptr_t)allocator.allocate(8, 32); /* 32 - 40 */
+ uintptr_t ptr4 = (uintptr_t)allocator.allocate(16, 8); /* 40 - 56 */
+ uintptr_t ptr5 = (uintptr_t)allocator.allocate(1, 8); /* 56 - 57 */
+ uintptr_t ptr6 = (uintptr_t)allocator.allocate(1, 4); /* 60 - 61 */
+ uintptr_t ptr7 = (uintptr_t)allocator.allocate(1, 1); /* 61 - 62 */
+
+ EXPECT_EQ(ptr2 - ptr1, 12); /* 12 - 0 = 12 */
+ EXPECT_EQ(ptr3 - ptr2, 20); /* 32 - 12 = 20 */
+ EXPECT_EQ(ptr4 - ptr3, 8); /* 40 - 32 = 8 */
+ EXPECT_EQ(ptr5 - ptr4, 16); /* 56 - 40 = 16 */
+ EXPECT_EQ(ptr6 - ptr5, 4); /* 60 - 56 = 4 */
+ EXPECT_EQ(ptr7 - ptr6, 1); /* 61 - 60 = 1 */
+}
+
+TEST(linear_allocator, CopyString)
+{
+ LinearAllocator<> allocator;
+ BLI::AlignedBuffer<256, 1> buffer;
+ allocator.provide_buffer(buffer);
+
+ StringRefNull ref1 = allocator.copy_string("Hello");
+ StringRefNull ref2 = allocator.copy_string("World");
+
+ EXPECT_EQ(ref1, "Hello");
+ EXPECT_EQ(ref2, "World");
+ EXPECT_EQ(ref2.data() - ref1.data(), 6);
+}
+
+TEST(linear_allocator, AllocateArray)
+{
+ LinearAllocator<> allocator;
+
+ MutableArrayRef<int> array = allocator.allocate_array<int>(5);
+ EXPECT_EQ(array.size(), 5);
+}
+
+TEST(linear_allocator, Construct)
+{
+ LinearAllocator<> allocator;
+
+ std::array<int, 5> values = {1, 2, 3, 4, 5};
+ Vector<int> *vector = allocator.construct<Vector<int>>(values);
+ EXPECT_EQ(vector->size(), 5);
+ EXPECT_EQ((*vector)[3], 4);
+ vector->~Vector();
+}
+
+TEST(linear_allocator, ConstructElementsAndPointerArray)
+{
+ LinearAllocator<> allocator;
+
+ std::array<int, 7> values = {1, 2, 3, 4, 5, 6, 7};
+ ArrayRef<Vector<int> *> vectors = allocator.construct_elements_and_pointer_array<Vector<int>>(
+ 5, values);
+
+ EXPECT_EQ(vectors.size(), 5);
+ EXPECT_EQ(vectors[3]->size(), 7);
+ EXPECT_EQ((*vectors[2])[5], 6);
+
+ for (Vector<int> *vector : vectors) {
+ vector->~Vector();
+ }
+}
+
+TEST(linear_allocator, ConstructArrayCopy)
+{
+ LinearAllocator<> allocator;
+
+ Vector<int> values = {1, 2, 3};
+ MutableArrayRef<int> array1 = allocator.construct_array_copy(values.as_ref());
+ MutableArrayRef<int> array2 = allocator.construct_array_copy(values.as_ref());
+ EXPECT_NE(array1.begin(), array2.begin());
+ EXPECT_EQ(array1.size(), 3);
+ EXPECT_EQ(array2.size(), 3);
+ EXPECT_EQ(array1[1], 2);
+ EXPECT_EQ(array2[2], 3);
+}
diff --git a/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc b/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc
index 9934d1a3337..023d02e5075 100644
--- a/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc
+++ b/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc
@@ -63,9 +63,9 @@ struct IndexedNode {
int index;
};
-void concurrent_insert(TaskPool *__restrict pool, void *taskdata, int /*threadid*/)
+void concurrent_insert(TaskPool *__restrict pool, void *taskdata)
{
- LockfreeLinkList *list = (LockfreeLinkList *)BLI_task_pool_userdata(pool);
+ LockfreeLinkList *list = (LockfreeLinkList *)BLI_task_pool_user_data(pool);
CHECK_NOTNULL(list);
IndexedNode *node = (IndexedNode *)MEM_mallocN(sizeof(IndexedNode), "test node");
node->index = POINTER_AS_INT(taskdata);
@@ -76,14 +76,12 @@ void concurrent_insert(TaskPool *__restrict pool, void *taskdata, int /*threadid
TEST(LockfreeLinkList, InsertMultipleConcurrent)
{
- static const int num_threads = 512;
static const int num_nodes = 655360;
/* Initialize list. */
LockfreeLinkList list;
BLI_linklist_lockfree_init(&list);
/* Initialize task scheduler and pool. */
- TaskScheduler *scheduler = BLI_task_scheduler_create(num_threads);
- TaskPool *pool = BLI_task_pool_create_suspended(scheduler, &list, TASK_PRIORITY_HIGH);
+ TaskPool *pool = BLI_task_pool_create_suspended(&list, TASK_PRIORITY_HIGH);
/* Push tasks to the pool. */
for (int i = 0; i < num_nodes; ++i) {
BLI_task_pool_push(pool, concurrent_insert, POINTER_FROM_INT(i), false, NULL);
@@ -112,5 +110,4 @@ TEST(LockfreeLinkList, InsertMultipleConcurrent)
/* Cleanup data. */
BLI_linklist_lockfree_free(&list, MEM_freeN);
BLI_task_pool_free(pool);
- BLI_task_scheduler_free(scheduler);
}
diff --git a/tests/gtests/blenlib/BLI_map_test.cc b/tests/gtests/blenlib/BLI_map_test.cc
index 7be23157e94..5a19216fa7c 100644
--- a/tests/gtests/blenlib/BLI_map_test.cc
+++ b/tests/gtests/blenlib/BLI_map_test.cc
@@ -1,5 +1,5 @@
-#include "BLI_map.h"
-#include "BLI_set.h"
+#include "BLI_map.hh"
+#include "BLI_set.hh"
#include "testing/testing.h"
using BLI::Map;
@@ -9,16 +9,20 @@ TEST(map, DefaultConstructor)
{
IntFloatMap map;
EXPECT_EQ(map.size(), 0);
+ EXPECT_TRUE(map.is_empty());
}
TEST(map, AddIncreasesSize)
{
IntFloatMap map;
EXPECT_EQ(map.size(), 0);
+ EXPECT_TRUE(map.is_empty());
map.add(2, 5.0f);
EXPECT_EQ(map.size(), 1);
+ EXPECT_FALSE(map.is_empty());
map.add(6, 2.0f);
EXPECT_EQ(map.size(), 2);
+ EXPECT_FALSE(map.is_empty());
}
TEST(map, Contains)
@@ -209,6 +213,17 @@ TEST(map, AddOverride)
EXPECT_EQ(map.lookup(3), 7.0f);
}
+TEST(map, LookupOrAddDefault)
+{
+ IntFloatMap map;
+ map.lookup_or_add_default(3) = 6;
+ EXPECT_EQ(map.lookup(3), 6);
+ map.lookup_or_add_default(5) = 2;
+ EXPECT_EQ(map.lookup(5), 2);
+ map.lookup_or_add_default(3) += 4;
+ EXPECT_EQ(map.lookup(3), 10);
+}
+
TEST(map, MoveConstructorSmall)
{
IntFloatMap map1;
diff --git a/tests/gtests/blenlib/BLI_optional_test.cc b/tests/gtests/blenlib/BLI_optional_test.cc
index a25a3cbd588..e0dec5681fe 100644
--- a/tests/gtests/blenlib/BLI_optional_test.cc
+++ b/tests/gtests/blenlib/BLI_optional_test.cc
@@ -1,4 +1,4 @@
-#include "BLI_optional.h"
+#include "BLI_optional.hh"
#include "testing/testing.h"
#include <string>
diff --git a/tests/gtests/blenlib/BLI_set_test.cc b/tests/gtests/blenlib/BLI_set_test.cc
index 555140f805c..90c052d7d2b 100644
--- a/tests/gtests/blenlib/BLI_set_test.cc
+++ b/tests/gtests/blenlib/BLI_set_test.cc
@@ -1,5 +1,5 @@
-#include "BLI_set.h"
-#include "BLI_vector.h"
+#include "BLI_set.hh"
+#include "BLI_vector.hh"
#include "testing/testing.h"
using BLI::Set;
@@ -10,6 +10,7 @@ TEST(set, Defaultconstructor)
{
IntSet set;
EXPECT_EQ(set.size(), 0);
+ EXPECT_TRUE(set.is_empty());
}
TEST(set, ContainsNotExistant)
@@ -22,8 +23,10 @@ TEST(set, ContainsExistant)
{
IntSet set;
EXPECT_FALSE(set.contains(5));
+ EXPECT_TRUE(set.is_empty());
set.add(5);
EXPECT_TRUE(set.contains(5));
+ EXPECT_FALSE(set.is_empty());
}
TEST(set, AddMany)
@@ -155,16 +158,6 @@ TEST(set, AddMultipleNew)
EXPECT_TRUE(a.contains(6));
}
-TEST(set, ToSmallVector)
-{
- IntSet a = {5, 2, 8};
- BLI::Vector<int> vec = a.to_small_vector();
- EXPECT_EQ(vec.size(), 3);
- EXPECT_TRUE(vec.contains(5));
- EXPECT_TRUE(vec.contains(2));
- EXPECT_TRUE(vec.contains(8));
-}
-
TEST(set, Iterator)
{
IntSet set = {1, 3, 2, 5, 4};
@@ -201,3 +194,11 @@ TEST(set, UniquePtrValues)
EXPECT_EQ(set.size(), 3);
}
+
+TEST(set, Clear)
+{
+ Set<int> set = {3, 4, 6, 7};
+ EXPECT_EQ(set.size(), 4);
+ set.clear();
+ EXPECT_EQ(set.size(), 0);
+}
diff --git a/tests/gtests/blenlib/BLI_stack_cxx_test.cc b/tests/gtests/blenlib/BLI_stack_cxx_test.cc
index 6376259927b..e49872f8643 100644
--- a/tests/gtests/blenlib/BLI_stack_cxx_test.cc
+++ b/tests/gtests/blenlib/BLI_stack_cxx_test.cc
@@ -1,4 +1,4 @@
-#include "BLI_stack_cxx.h"
+#include "BLI_stack.hh"
#include "testing/testing.h"
using BLI::Stack;
diff --git a/tests/gtests/blenlib/BLI_string_map_test.cc b/tests/gtests/blenlib/BLI_string_map_test.cc
index 4cb67d5fbac..41cda920a89 100644
--- a/tests/gtests/blenlib/BLI_string_map_test.cc
+++ b/tests/gtests/blenlib/BLI_string_map_test.cc
@@ -1,5 +1,5 @@
-#include "BLI_string_map.h"
-#include "BLI_vector.h"
+#include "BLI_string_map.hh"
+#include "BLI_vector.hh"
#include "testing/testing.h"
using namespace BLI;
@@ -232,3 +232,20 @@ TEST(string_map, UniquePtrValues)
std::unique_ptr<int> *b = map.lookup_ptr("A");
EXPECT_EQ(a.get(), b->get());
}
+
+TEST(string_map, AddOrModify)
+{
+ StringMap<int> map;
+ auto create_func = [](int *value) {
+ *value = 10;
+ return true;
+ };
+ auto modify_func = [](int *value) {
+ *value += 5;
+ return false;
+ };
+ EXPECT_TRUE(map.add_or_modify("Hello", create_func, modify_func));
+ EXPECT_EQ(map.lookup("Hello"), 10);
+ EXPECT_FALSE(map.add_or_modify("Hello", create_func, modify_func));
+ EXPECT_EQ(map.lookup("Hello"), 15);
+}
diff --git a/tests/gtests/blenlib/BLI_string_ref_test.cc b/tests/gtests/blenlib/BLI_string_ref_test.cc
index a268bf3215a..393f28d4fc1 100644
--- a/tests/gtests/blenlib/BLI_string_ref_test.cc
+++ b/tests/gtests/blenlib/BLI_string_ref_test.cc
@@ -1,5 +1,5 @@
-#include "BLI_string_ref.h"
-#include "BLI_vector.h"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
#include "testing/testing.h"
using BLI::StringRef;
@@ -237,3 +237,14 @@ TEST(string_ref, Substr)
EXPECT_EQ(ref.substr(3, 4), "lo w");
EXPECT_EQ(ref.substr(6, 5), "world");
}
+
+TEST(string_ref, Copy)
+{
+ StringRef ref("hello");
+ char dst[10];
+ memset(dst, 0xFF, 10);
+ ref.copy(dst);
+ EXPECT_EQ(dst[5], '\0');
+ EXPECT_EQ(dst[6], 0xFF);
+ EXPECT_EQ(ref, dst);
+}
diff --git a/tests/gtests/blenlib/BLI_task_performance_test.cc b/tests/gtests/blenlib/BLI_task_performance_test.cc
index db596340464..06e832bdb5e 100644
--- a/tests/gtests/blenlib/BLI_task_performance_test.cc
+++ b/tests/gtests/blenlib/BLI_task_performance_test.cc
@@ -36,92 +36,6 @@ static uint gen_pseudo_random_number(uint num)
return ((num & 255) << 6) + 1;
}
-/* *** Parallel iterations over range of indices. *** */
-
-static void task_parallel_range_func(void *UNUSED(userdata),
- int index,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- const uint limit = gen_pseudo_random_number((uint)index);
- for (uint i = (uint)index; i < limit;) {
- i += gen_pseudo_random_number(i);
- }
-}
-
-static void task_parallel_range_test_do(const char *id,
- const int num_items,
- const bool use_threads)
-{
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = use_threads;
-
- double averaged_timing = 0.0;
- for (int i = 0; i < NUM_RUN_AVERAGED; i++) {
- const double init_time = PIL_check_seconds_timer();
- for (int j = 0; j < 10; j++) {
- BLI_task_parallel_range(i + j, i + j + num_items, NULL, task_parallel_range_func, &settings);
- }
- averaged_timing += PIL_check_seconds_timer() - init_time;
- }
-
- printf("\t%s: non-pooled done in %fs on average over %d runs\n",
- id,
- averaged_timing / NUM_RUN_AVERAGED,
- NUM_RUN_AVERAGED);
-
- averaged_timing = 0.0;
- for (int i = 0; i < NUM_RUN_AVERAGED; i++) {
- const double init_time = PIL_check_seconds_timer();
- TaskParallelRangePool *range_pool = BLI_task_parallel_range_pool_init(&settings);
- for (int j = 0; j < 10; j++) {
- BLI_task_parallel_range_pool_push(
- range_pool, i + j, i + j + num_items, NULL, task_parallel_range_func, &settings);
- }
- BLI_task_parallel_range_pool_work_and_wait(range_pool);
- BLI_task_parallel_range_pool_free(range_pool);
- averaged_timing += PIL_check_seconds_timer() - init_time;
- }
-
- printf("\t%s: pooled done in %fs on average over %d runs\n",
- id,
- averaged_timing / NUM_RUN_AVERAGED,
- NUM_RUN_AVERAGED);
-}
-
-TEST(task, RangeIter10KNoThread)
-{
- task_parallel_range_test_do(
- "Range parallel iteration - Single thread - 10K items", 10000, false);
-}
-
-TEST(task, RangeIter10k)
-{
- task_parallel_range_test_do("Range parallel iteration - Threaded - 10K items", 10000, true);
-}
-
-TEST(task, RangeIter100KNoThread)
-{
- task_parallel_range_test_do(
- "Range parallel iteration - Single thread - 100K items", 100000, false);
-}
-
-TEST(task, RangeIter100k)
-{
- task_parallel_range_test_do("Range parallel iteration - Threaded - 100K items", 100000, true);
-}
-
-TEST(task, RangeIter1000KNoThread)
-{
- task_parallel_range_test_do(
- "Range parallel iteration - Single thread - 1000K items", 1000000, false);
-}
-
-TEST(task, RangeIter1000k)
-{
- task_parallel_range_test_do("Range parallel iteration - Threaded - 1000K items", 1000000, true);
-}
-
/* *** Parallel iterations over double-linked list items. *** */
static void task_listbase_light_iter_func(void *UNUSED(userdata),
diff --git a/tests/gtests/blenlib/BLI_task_test.cc b/tests/gtests/blenlib/BLI_task_test.cc
index d4ab9de13c4..ed300b3f238 100644
--- a/tests/gtests/blenlib/BLI_task_test.cc
+++ b/tests/gtests/blenlib/BLI_task_test.cc
@@ -27,17 +27,19 @@ static void task_range_iter_func(void *userdata, int index, const TaskParallelTL
// printf("%d, %d, %d\n", index, data[index], *((int *)tls->userdata_chunk));
}
-static void task_range_iter_finalize_func(void *__restrict userdata,
- void *__restrict userdata_chunk)
+static void task_range_iter_reduce_func(const void *__restrict UNUSED(userdata),
+ void *__restrict join_v,
+ void *__restrict userdata_chunk)
{
- int *data = (int *)userdata;
- data[NUM_ITEMS] += *(int *)userdata_chunk;
+ int *join = (int *)join_v;
+ int *chunk = (int *)userdata_chunk;
+ *join += *chunk;
// printf("%d, %d\n", data[NUM_ITEMS], *((int *)userdata_chunk));
}
TEST(task, RangeIter)
{
- int data[NUM_ITEMS + 1] = {0};
+ int data[NUM_ITEMS] = {0};
int sum = 0;
BLI_threadapi_init();
@@ -48,11 +50,11 @@ TEST(task, RangeIter)
settings.userdata_chunk = &sum;
settings.userdata_chunk_size = sizeof(sum);
- settings.func_finalize = task_range_iter_finalize_func;
+ settings.func_reduce = task_range_iter_reduce_func;
BLI_task_parallel_range(0, NUM_ITEMS, data, task_range_iter_func, &settings);
- /* Those checks should ensure us all items of the listbase were processed once, and only once -
+ /* Those checks should ensure us all items of the listbase were processed once, and only once
* as expected. */
int expected_sum = 0;
@@ -60,79 +62,7 @@ TEST(task, RangeIter)
EXPECT_EQ(data[i], i);
expected_sum += i;
}
- EXPECT_EQ(data[NUM_ITEMS], expected_sum);
-
- BLI_threadapi_exit();
-}
-
-TEST(task, RangeIterPool)
-{
- const int num_tasks = 10;
- int data[num_tasks][NUM_ITEMS + 1] = {{0}};
- int sum = 0;
-
- BLI_threadapi_init();
-
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 1;
-
- TaskParallelRangePool *range_pool = BLI_task_parallel_range_pool_init(&settings);
-
- for (int j = 0; j < num_tasks; j++) {
- settings.userdata_chunk = &sum;
- settings.userdata_chunk_size = sizeof(sum);
- settings.func_finalize = task_range_iter_finalize_func;
-
- BLI_task_parallel_range_pool_push(
- range_pool, 0, NUM_ITEMS, data[j], task_range_iter_func, &settings);
- }
-
- BLI_task_parallel_range_pool_work_and_wait(range_pool);
-
- /* Those checks should ensure us all items of the listbase were processed once, and only once -
- * as expected. */
-
- for (int j = 0; j < num_tasks; j++) {
- int expected_sum = 0;
- for (int i = 0; i < NUM_ITEMS; i++) {
- // EXPECT_EQ(data[j][i], i);
- expected_sum += i;
- }
- EXPECT_EQ(data[j][NUM_ITEMS], expected_sum);
- }
-
- /* A pool can be re-used untill it is freed. */
-
- for (int j = 0; j < num_tasks; j++) {
- memset(data[j], 0, sizeof(data[j]));
- }
- sum = 0;
-
- for (int j = 0; j < num_tasks; j++) {
- settings.userdata_chunk = &sum;
- settings.userdata_chunk_size = sizeof(sum);
- settings.func_finalize = task_range_iter_finalize_func;
-
- BLI_task_parallel_range_pool_push(
- range_pool, 0, NUM_ITEMS, data[j], task_range_iter_func, &settings);
- }
-
- BLI_task_parallel_range_pool_work_and_wait(range_pool);
-
- BLI_task_parallel_range_pool_free(range_pool);
-
- /* Those checks should ensure us all items of the listbase were processed once, and only once -
- * as expected. */
-
- for (int j = 0; j < num_tasks; j++) {
- int expected_sum = 0;
- for (int i = 0; i < NUM_ITEMS; i++) {
- // EXPECT_EQ(data[j][i], i);
- expected_sum += i;
- }
- EXPECT_EQ(data[j][NUM_ITEMS], expected_sum);
- }
+ EXPECT_EQ(sum, expected_sum);
BLI_threadapi_exit();
}
diff --git a/tests/gtests/blenlib/BLI_vector_set_test.cc b/tests/gtests/blenlib/BLI_vector_set_test.cc
index 5ec51337aa7..bfdd47ccb13 100644
--- a/tests/gtests/blenlib/BLI_vector_set_test.cc
+++ b/tests/gtests/blenlib/BLI_vector_set_test.cc
@@ -1,4 +1,4 @@
-#include "BLI_vector_set.h"
+#include "BLI_vector_set.hh"
#include "testing/testing.h"
using BLI::VectorSet;
@@ -8,6 +8,7 @@ TEST(vector_set, DefaultConstructor)
{
IntVectorSet set;
EXPECT_EQ(set.size(), 0);
+ EXPECT_TRUE(set.is_empty());
}
TEST(vector_set, InitializerListConstructor_WithoutDuplicates)
@@ -39,6 +40,17 @@ TEST(vector_set, Copy)
EXPECT_EQ(set2.index(2), 1);
}
+TEST(vector_set, CopyAssignment)
+{
+ IntVectorSet set1 = {1, 2, 3};
+ IntVectorSet set2 = {};
+ set2 = set1;
+ EXPECT_EQ(set1.size(), 3);
+ EXPECT_EQ(set2.size(), 3);
+ EXPECT_EQ(set1.index(2), 1);
+ EXPECT_EQ(set2.index(2), 1);
+}
+
TEST(vector_set, Move)
{
IntVectorSet set1 = {1, 2, 3};
@@ -47,11 +59,22 @@ TEST(vector_set, Move)
EXPECT_EQ(set2.size(), 3);
}
+TEST(vector_set, MoveAssignment)
+{
+ IntVectorSet set1 = {1, 2, 3};
+ IntVectorSet set2 = {};
+ set2 = std::move(set1);
+ EXPECT_EQ(set1.size(), 0);
+ EXPECT_EQ(set2.size(), 3);
+}
+
TEST(vector_set, AddNewIncreasesSize)
{
IntVectorSet set;
+ EXPECT_TRUE(set.is_empty());
EXPECT_EQ(set.size(), 0);
set.add(5);
+ EXPECT_FALSE(set.is_empty());
EXPECT_EQ(set.size(), 1);
}
diff --git a/tests/gtests/blenlib/BLI_vector_test.cc b/tests/gtests/blenlib/BLI_vector_test.cc
index 2402ee9627f..e5a1ca2b200 100644
--- a/tests/gtests/blenlib/BLI_vector_test.cc
+++ b/tests/gtests/blenlib/BLI_vector_test.cc
@@ -1,4 +1,4 @@
-#include "BLI_vector.h"
+#include "BLI_vector.hh"
#include "testing/testing.h"
#include <forward_list>
@@ -45,7 +45,7 @@ struct TestListValue {
int value;
};
-TEST(vector, IntrusiveListBaseConstructor)
+TEST(vector, ListBaseConstructor)
{
TestListValue *value1 = new TestListValue{0, 0, 4};
TestListValue *value2 = new TestListValue{0, 0, 5};
@@ -55,7 +55,7 @@ TEST(vector, IntrusiveListBaseConstructor)
BLI_addtail(&list, value1);
BLI_addtail(&list, value2);
BLI_addtail(&list, value3);
- Vector<TestListValue *> vec(list, true);
+ Vector<TestListValue *> vec(list);
EXPECT_EQ(vec.size(), 3);
EXPECT_EQ(vec[0]->value, 4);
@@ -345,14 +345,14 @@ TEST(vector, RemoveLast)
EXPECT_EQ(vec.size(), 0);
}
-TEST(vector, Empty)
+TEST(vector, IsEmpty)
{
IntVector vec;
- EXPECT_TRUE(vec.empty());
+ EXPECT_TRUE(vec.is_empty());
vec.append(1);
- EXPECT_FALSE(vec.empty());
+ EXPECT_FALSE(vec.is_empty());
vec.remove_last();
- EXPECT_TRUE(vec.empty());
+ EXPECT_TRUE(vec.is_empty());
}
TEST(vector, RemoveReorder)
@@ -368,7 +368,7 @@ TEST(vector, RemoveReorder)
vec.remove_and_reorder(0);
EXPECT_EQ(vec[0], 7);
vec.remove_and_reorder(0);
- EXPECT_TRUE(vec.empty());
+ EXPECT_TRUE(vec.is_empty());
}
TEST(vector, RemoveFirstOccurrenceAndReorder)
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index 119b54fa0d4..a0621448630 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -52,6 +52,7 @@ BLENDER_TEST(BLI_heap "bf_blenlib")
BLENDER_TEST(BLI_heap_simple "bf_blenlib")
BLENDER_TEST(BLI_index_range "bf_blenlib")
BLENDER_TEST(BLI_kdopbvh "bf_blenlib;bf_intern_numaapi")
+BLENDER_TEST(BLI_linear_allocator "bf_blenlib")
BLENDER_TEST(BLI_linklist_lockfree "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_listbase "bf_blenlib")
BLENDER_TEST(BLI_map "bf_blenlib")
diff --git a/tests/gtests/usd/hierarchy_context_order_test.cc b/tests/gtests/usd/hierarchy_context_order_test.cc
index ce3b43484e7..a6a8aa16766 100644
--- a/tests/gtests/usd/hierarchy_context_order_test.cc
+++ b/tests/gtests/usd/hierarchy_context_order_test.cc
@@ -44,9 +44,9 @@ TEST_F(HierarchyContextOrderTest, ObjectPointerTest)
ctx_b.object = fake_pointer(2);
ctx_b.duplicator = nullptr;
- EXPECT_EQ(true, ctx_a < ctx_b);
- EXPECT_EQ(false, ctx_b < ctx_a);
- EXPECT_EQ(false, ctx_a < ctx_a);
+ EXPECT_LT(ctx_a, ctx_b);
+ EXPECT_FALSE(ctx_b < ctx_a);
+ EXPECT_FALSE(ctx_a < ctx_a);
}
TEST_F(HierarchyContextOrderTest, DuplicatorPointerTest)
@@ -61,9 +61,9 @@ TEST_F(HierarchyContextOrderTest, DuplicatorPointerTest)
ctx_b.duplicator = fake_pointer(1);
ctx_b.export_name = "B";
- EXPECT_EQ(true, ctx_a < ctx_b);
- EXPECT_EQ(false, ctx_b < ctx_a);
- EXPECT_EQ(false, ctx_a < ctx_a);
+ EXPECT_LT(ctx_a, ctx_b);
+ EXPECT_FALSE(ctx_b < ctx_a);
+ EXPECT_FALSE(ctx_a < ctx_a);
}
TEST_F(HierarchyContextOrderTest, ExportParentTest)
@@ -76,9 +76,9 @@ TEST_F(HierarchyContextOrderTest, ExportParentTest)
ctx_b.object = fake_pointer(1);
ctx_b.export_parent = fake_pointer(2);
- EXPECT_EQ(true, ctx_a < ctx_b);
- EXPECT_EQ(false, ctx_b < ctx_a);
- EXPECT_EQ(false, ctx_a < ctx_a);
+ EXPECT_LT(ctx_a, ctx_b);
+ EXPECT_FALSE(ctx_b < ctx_a);
+ EXPECT_FALSE(ctx_a < ctx_a);
}
TEST_F(HierarchyContextOrderTest, TransitiveTest)
@@ -107,17 +107,17 @@ TEST_F(HierarchyContextOrderTest, TransitiveTest)
ctx_d.duplicator = nullptr;
ctx_d.export_name = "D";
- EXPECT_EQ(true, ctx_a < ctx_b);
- EXPECT_EQ(true, ctx_a < ctx_c);
- EXPECT_EQ(true, ctx_a < ctx_d);
- EXPECT_EQ(true, ctx_b < ctx_c);
- EXPECT_EQ(true, ctx_b < ctx_d);
- EXPECT_EQ(true, ctx_c < ctx_d);
-
- EXPECT_EQ(false, ctx_b < ctx_a);
- EXPECT_EQ(false, ctx_c < ctx_a);
- EXPECT_EQ(false, ctx_d < ctx_a);
- EXPECT_EQ(false, ctx_c < ctx_b);
- EXPECT_EQ(false, ctx_d < ctx_b);
- EXPECT_EQ(false, ctx_d < ctx_c);
+ EXPECT_LT(ctx_a, ctx_b);
+ EXPECT_LT(ctx_a, ctx_c);
+ EXPECT_LT(ctx_a, ctx_d);
+ EXPECT_LT(ctx_b, ctx_c);
+ EXPECT_LT(ctx_b, ctx_d);
+ EXPECT_LT(ctx_c, ctx_d);
+
+ EXPECT_FALSE(ctx_b < ctx_a);
+ EXPECT_FALSE(ctx_c < ctx_a);
+ EXPECT_FALSE(ctx_d < ctx_a);
+ EXPECT_FALSE(ctx_c < ctx_b);
+ EXPECT_FALSE(ctx_d < ctx_b);
+ EXPECT_FALSE(ctx_d < ctx_c);
}
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 2d6dc4af40e..a3df01fdbe2 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -48,18 +48,14 @@ endfunction()
# Run Python script outside Blender.
function(add_python_test testname testscript)
- if(MSVC)
- add_test(
- NAME ${testname}
- COMMAND ${TEST_PYTHON_EXE} ${testscript} ${ARGN}
- )
- else()
- add_test(
- NAME ${testname}
- COMMAND ${testscript} ${ARGN}
- )
+ if(NOT TEST_PYTHON_EXE)
+ message(FATAL_ERROR "No Python configured for running tests, set TEST_PYTHON_EXE.")
endif()
+ add_test(
+ NAME ${testname}
+ COMMAND ${TEST_PYTHON_EXE} ${testscript} ${ARGN}
+ )
set_tests_properties(${testname} PROPERTIES ENVIRONMENT LSAN_OPTIONS=exitcode=0)
endfunction()
diff --git a/tests/python/alembic_tests.py b/tests/python/alembic_tests.py
index 9de1bc06d84..9de1bc06d84 100755..100644
--- a/tests/python/alembic_tests.py
+++ b/tests/python/alembic_tests.py
diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py
index 79ba11fdd44..79ba11fdd44 100755..100644
--- a/tests/python/cycles_render_tests.py
+++ b/tests/python/cycles_render_tests.py
diff --git a/tests/python/eevee_render_tests.py b/tests/python/eevee_render_tests.py
index a7130136d0a..a7130136d0a 100755..100644
--- a/tests/python/eevee_render_tests.py
+++ b/tests/python/eevee_render_tests.py
diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py
index 92734b5bc7d..92734b5bc7d 100755..100644
--- a/tests/python/ffmpeg_tests.py
+++ b/tests/python/ffmpeg_tests.py
diff --git a/tests/python/opengl_draw_tests.py b/tests/python/opengl_draw_tests.py
index ab4df63afd9..ab4df63afd9 100755..100644
--- a/tests/python/opengl_draw_tests.py
+++ b/tests/python/opengl_draw_tests.py
diff --git a/tests/python/workbench_render_tests.py b/tests/python/workbench_render_tests.py
index 155b54098a8..155b54098a8 100755..100644
--- a/tests/python/workbench_render_tests.py
+++ b/tests/python/workbench_render_tests.py