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:
authorJacques Lucke <jacques@blender.org>2020-05-04 13:29:39 +0300
committerJacques Lucke <jacques@blender.org>2020-05-04 13:29:39 +0300
commitdc1c562f632e1370702e85df0711929f3f77d7ea (patch)
treec99ea932ed0c7ac04ecce774377803e7a5dc2fac
parent10fad7c88db642277be784ba77941faa7abc5d9a (diff)
parent9adb81f58494731438f3afdcbacb1599a4a32bb9 (diff)
Merge branch 'master' into simulation-access-modifier
-rw-r--r--CMakeLists.txt26
-rw-r--r--build_files/build_environment/cmake/bzip2.cmake2
-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
-rwxr-xr-xbuild_files/build_environment/install_deps.sh7
-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.cmake22
-rw-r--r--build_files/cmake/platform/platform_win32.cmake26
-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.py17
-rw-r--r--intern/cycles/blender/blender_sync.cpp2
-rw-r--r--intern/cycles/bvh/bvh_optix.cpp38
-rw-r--r--intern/cycles/kernel/kernel_compat_cuda.h1
-rw-r--r--intern/cycles/kernel/kernel_compat_opencl.h1
-rw-r--r--intern/cycles/kernel/kernel_compat_optix.h1
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp18
-rw-r--r--intern/cycles/kernel/osl/osl_services.h17
-rw-r--r--intern/cycles/kernel/svm/svm_voronoi.h21
-rw-r--r--intern/cycles/render/mesh_volume.cpp10
-rw-r--r--intern/cycles/render/session.cpp85
-rw-r--r--intern/cycles/render/session.h6
-rw-r--r--intern/cycles/render/tile.cpp4
-rw-r--r--intern/cycles/render/tile.h2
-rw-r--r--intern/cycles/util/util_defines.h1
-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.cpp9
-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.h10
-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.cc181
-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.cpp1666
-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.h7
-rw-r--r--intern/mantaflow/intern/strings/smoke_script.h7
-rw-r--r--intern/string/CMakeLists.txt38
-rw-r--r--intern/string/STR_String.h366
-rw-r--r--intern/string/intern/STR_String.cpp637
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py1
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py9
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py8
-rw-r--r--release/scripts/startup/bl_operators/wm.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py19
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py34
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py5
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_texture.py2
-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_outliner.py6
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py16
-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_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_idprop.h11
-rw-r--r--source/blender/blenkernel/BKE_image.h2
-rw-r--r--source/blender/blenkernel/BKE_multires.h23
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-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_sound.h6
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h6
-rw-r--r--source/blender/blenkernel/CMakeLists.txt6
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c5
-rw-r--r--source/blender/blenkernel/intern/anim_data.c1
-rw-r--r--source/blender/blenkernel/intern/brush.c62
-rw-r--r--source/blender/blenkernel/intern/constraint.c2
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c2
-rw-r--r--source/blender/blenkernel/intern/displist.c37
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c7
-rw-r--r--source/blender/blenkernel/intern/fcurve.c1961
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c1294
-rw-r--r--source/blender/blenkernel/intern/fluid.c58
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.c6
-rw-r--r--source/blender/blenkernel/intern/idprop.c41
-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/lib_query.c162
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c8
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c8
-rw-r--r--source/blender/blenkernel/intern/movieclip.c5
-rw-r--r--source/blender/blenkernel/intern/multires.c20
-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/object.c1
-rw-r--r--source/blender/blenkernel/intern/ocean.c35
-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/pbvh.c28
-rw-r--r--source/blender/blenkernel/intern/seqcache.c8
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c70
-rw-r--r--source/blender/blenkernel/intern/seqprefetch.c28
-rw-r--r--source/blender/blenkernel/intern/sequencer.c63
-rw-r--r--source/blender/blenkernel/intern/sound.c16
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c64
-rw-r--r--source/blender/blenkernel/intern/subdiv_deform.c40
-rw-r--r--source/blender/blenkernel/intern/subdiv_foreach.c80
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c120
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c12
-rw-r--r--source/blender/blenlib/BLI_array.hh7
-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_gsqueue.h2
-rw-r--r--source/blender/blenlib/BLI_lasso_2d.h10
-rw-r--r--source/blender/blenlib/BLI_map.hh21
-rw-r--r--source/blender/blenlib/BLI_math_vector.h5
-rw-r--r--source/blender/blenlib/BLI_open_addressing.hh83
-rw-r--r--source/blender/blenlib/BLI_set.hh14
-rw-r--r--source/blender/blenlib/BLI_system.h4
-rw-r--r--source/blender/blenlib/BLI_task.h66
-rw-r--r--source/blender/blenlib/BLI_threads.h2
-rw-r--r--source/blender/blenlib/BLI_vector.hh6
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh5
-rw-r--r--source/blender/blenlib/CMakeLists.txt18
-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.c341
-rw-r--r--source/blender/blenlib/intern/task_pool.cc1147
-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/blenloader/intern/readfile.c15
-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/writefile.c1
-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.cc98
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc1
-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.cc65
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc1
-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.cc7
-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.h11
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc58
-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.cc1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h1
-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/overlay/overlay_gpencil.c13
-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/editors/animation/anim_filter.c1
-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_add.c14
-rw-r--r--source/blender/editors/armature/armature_edit.c3
-rw-r--r--source/blender/editors/armature/armature_intern.h1
-rw-r--r--source/blender/editors/armature/armature_ops.c1
-rw-r--r--source/blender/editors/armature/armature_relations.c4
-rw-r--r--source/blender/editors/armature/pose_group.c3
-rw-r--r--source/blender/editors/armature/pose_select.c66
-rw-r--r--source/blender/editors/curve/editcurve.c4
-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.c16
-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_paint.c21
-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_image.h14
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h4
-rw-r--r--source/blender/editors/include/ED_outliner.h3
-rw-r--r--source/blender/editors/include/ED_particle.h2
-rw-r--r--source/blender/editors/include/UI_interface.h1
-rw-r--r--source/blender/editors/include/UI_view2d.h23
-rw-r--r--source/blender/editors/interface/interface_anim.c1
-rw-r--r--source/blender/editors/interface/interface_handlers.c80
-rw-r--r--source/blender/editors/interface/interface_panel.c19
-rw-r--r--source/blender/editors/interface/interface_templates.c69
-rw-r--r--source/blender/editors/interface/interface_widgets.c13
-rw-r--r--source/blender/editors/interface/view2d.c20
-rw-r--r--source/blender/editors/mask/mask_select.c18
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c8
-rw-r--r--source/blender/editors/object/CMakeLists.txt2
-rw-r--r--source/blender/editors/object/object_add.c1
-rw-r--r--source/blender/editors/object/object_intern.h2
-rw-r--r--source/blender/editors/object/object_modifier.c142
-rw-r--r--source/blender/editors/object/object_ops.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c15
-rw-r--r--source/blender/editors/render/render_opengl.c17
-rw-r--r--source/blender/editors/screen/area.c12
-rw-r--r--source/blender/editors/screen/screen_ops.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c4
-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.c208
-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.c49
-rw-r--r--source/blender/editors/space_clip/clip_editor.c7
-rw-r--r--source/blender/editors/space_clip/clip_ops.c7
-rw-r--r--source/blender/editors/space_clip/tracking_select.c22
-rw-r--r--source/blender/editors/space_file/filelist.c8
-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_buttons.c4
-rw-r--r--source/blender/editors/space_image/image_edit.c11
-rw-r--r--source/blender/editors/space_info/info_stats.c33
-rw-r--r--source/blender/editors/space_node/drawnode.c862
-rw-r--r--source/blender/editors/space_node/node_select.c19
-rw-r--r--source/blender/editors/space_node/node_templates.c98
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c38
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c200
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h8
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c3
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c16
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c208
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c2
-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.h24
-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.c14
-rw-r--r--source/blender/editors/transform/transform_convert.h8
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c7
-rw-r--r--source/blender/editors/transform/transform_generics.c133
-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_orientations.c52
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt1
-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.txt2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c2
-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.c3
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c26
-rw-r--r--source/blender/imbuf/intern/imageprocess.c12
-rw-r--r--source/blender/makesdna/DNA_ID.h12
-rw-r--r--source/blender/makesdna/DNA_fluid_types.h3
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h1
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c1
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c7
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c2
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c13
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c2
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c14
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c14
-rw-r--r--source/blender/makesrna/intern/rna_xr.c16
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c3
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c4
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c6
-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/render/extern/include/RE_render_ext.h22
-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_playanim.c8
-rw-r--r--source/blender/windowmanager/intern/wm_window.c77
-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/blender.map45
-rw-r--r--source/creator/creator.c4
-rw-r--r--source/creator/creator_signals.c86
-rw-r--r--tests/CMakeLists.txt3
-rw-r--r--tests/gtests/blenkernel/BKE_armature_test.cc2
-rw-r--r--tests/gtests/blenkernel/BKE_fcurve_test.cc211
-rw-r--r--tests/gtests/blenkernel/CMakeLists.txt3
-rw-r--r--tests/gtests/blenlib/BLI_linklist_lockfree_test.cc7
-rw-r--r--tests/gtests/blenlib/BLI_map_test.cc15
-rw-r--r--tests/gtests/blenlib/BLI_set_test.cc11
-rw-r--r--tests/gtests/blenlib/BLI_task_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_vector_set_test.cc3
-rw-r--r--tests/gtests/blenlib/BLI_vector_test.cc10
-rw-r--r--tests/python/CMakeLists.txt16
-rw-r--r--tests/python/bevel_operator.py7
-rw-r--r--tests/python/bl_alembic_io_test.py10
-rw-r--r--tests/python/bl_blendfile_io.py7
-rw-r--r--tests/python/bl_blendfile_liblink.py7
-rw-r--r--tests/python/bl_bundled_modules.py2
-rw-r--r--tests/python/bl_constraints.py10
-rw-r--r--tests/python/bl_load_addons.py9
-rw-r--r--tests/python/bl_load_py_modules.py8
-rw-r--r--tests/python/bl_mesh_modifiers.py12
-rw-r--r--tests/python/bl_mesh_validate.py8
-rw-r--r--tests/python/bl_pyapi_idprop_datablock.py10
-rw-r--r--tests/python/bl_test.py15
-rw-r--r--tests/python/boolean_operator.py7
-rw-r--r--tests/python/modifiers.py7
-rw-r--r--tests/python/modules/mesh_test.py85
-rw-r--r--tests/python/operators.py8
-rw-r--r--tests/python/physics_cloth.py51
-rw-r--r--tests/python/physics_softbody.py51
479 files changed, 16980 insertions, 12016 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9f0ff3d1427..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)
@@ -543,6 +546,12 @@ if(WIN32)
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.
@@ -689,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/build_files/build_environment/cmake/bzip2.cmake b/build_files/build_environment/cmake/bzip2.cmake
index fbf5551e719..bb2be7c634a 100644
--- a/build_files/build_environment/cmake/bzip2.cmake
+++ b/build_files/build_environment/cmake/bzip2.cmake
@@ -25,6 +25,8 @@ if(UNIX AND NOT APPLE)
set(BZIP2_CFLAGS "-fPIC -Wall -Winline -O2 -g -D_FILE_OFFSET_BITS=64")
set(BZIP2_CONFIGURE_ENV ${BZIP2_CONFIGURE_ENV} && export LDFLAGS=${BZIP2_LDFLAGS} && export CFLAGS=${BZIP2_CFLAGS}
&& export PREFIX=${BZIP2_PREFIX})
+else()
+ set(BZIP2_CONFIGURE_ENV ${CONFIGURE_ENV})
endif()
ExternalProject_Add(external_bzip2
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/install_deps.sh b/build_files/build_environment/install_deps.sh
index e8f49c0c75c..6a247e81148 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -2654,7 +2654,7 @@ compile_USD() {
cd $CWD
INFO "Done compiling USD-$USD_VERSION!"
- _is_building=true
+ _is_building=false
else
INFO "Own USD-$USD_VERSION is up to date, nothing to do!"
INFO "If you want to force rebuild of this lib, use the --force-usd option."
@@ -5354,6 +5354,11 @@ print_info() {
_1="-D WITH_USD=ON"
PRINT " $_1"
_buildargs="$_buildargs $_1"
+ if [ -d $INST/usd ]; then
+ _1="-D USD_ROOT_DIR=$INST/usd"
+ PRINT " $_1"
+ _buildargs="$_buildargs $_1"
+ fi
fi
if [ "$NO_SYSTEM_GLEW" = true ]; then
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 8a89ce40432..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})
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index f882ff6238b..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
)
@@ -136,6 +140,11 @@ add_definitions(-D_WIN32_WINNT=0x601)
include(build_files/cmake/platform/platform_win32_bundle_crt.cmake)
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 ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference")
@@ -168,12 +177,12 @@ 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")
-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")
+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)
@@ -186,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)
@@ -586,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/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 92f0a8fb830..08641c05941 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -770,8 +770,9 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
col.prop(view_layer, "use_strand", text="Hair")
col.prop(view_layer, "use_volumes", text="Volumes")
if with_freestyle:
- 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):
@@ -1409,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')
@@ -1458,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'):
@@ -1477,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')
@@ -1664,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")
@@ -1682,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
@@ -1700,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')
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index f4c100bcd2b..0c120b944a7 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -108,7 +108,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
}
if (dicing_prop_changed) {
- for (const pair<GeometryKey, Geometry *> &iter : geometry_map.key_to_scene_data()) {
+ for (const pair<const GeometryKey, Geometry *> &iter : geometry_map.key_to_scene_data()) {
Geometry *geom = iter.second;
if (geom->type == Geometry::MESH) {
Mesh *mesh = static_cast<Mesh *>(geom);
diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp
index 26b64c24db5..740994b2ebc 100644
--- a/intern/cycles/bvh/bvh_optix.cpp
+++ b/intern/cycles/bvh/bvh_optix.cpp
@@ -156,6 +156,19 @@ void BVHOptiX::pack_tlas()
PackedBVH &bvh_pack = geom->bvh->pack;
int geom_prim_offset = geom->prim_offset;
+ // Merge visibility flags of all objects and fix object indices for non-instanced geometry
+ int object_index = 0; // Unused for instanced geometry
+ int object_visibility = 0;
+ foreach (Object *ob, objects) {
+ if (ob->geometry == geom) {
+ object_visibility |= ob->visibility_for_tracing();
+ if (!geom->is_instanced()) {
+ object_index = ob->get_device_index();
+ break;
+ }
+ }
+ }
+
// Merge primitive, object and triangle indexes
if (!bvh_pack.prim_index.empty()) {
int *bvh_prim_type = &bvh_pack.prim_type[0];
@@ -174,8 +187,8 @@ void BVHOptiX::pack_tlas()
}
pack_prim_type[pack_offset] = bvh_prim_type[i];
- pack_prim_object[pack_offset] = 0; // Unused for instanced geometry
- pack_prim_visibility[pack_offset] = bvh_prim_visibility[i];
+ pack_prim_object[pack_offset] = object_index;
+ pack_prim_visibility[pack_offset] = bvh_prim_visibility[i] | object_visibility;
}
}
@@ -188,27 +201,6 @@ void BVHOptiX::pack_tlas()
pack_verts_offset += prim_tri_size;
}
}
-
- // Merge visibility flags of all objects and fix object indices for non-instanced geometry
- foreach (Object *ob, objects) {
- Geometry *const geom = ob->geometry;
- size_t num_primitives = 0;
-
- if (geom->type == Geometry::MESH) {
- num_primitives = static_cast<Mesh *const>(geom)->num_triangles();
- }
- else if (geom->type == Geometry::HAIR) {
- num_primitives = static_cast<Hair *const>(geom)->num_segments();
- }
-
- for (size_t i = 0; i < num_primitives; ++i) {
- if (!geom->is_instanced()) {
- assert(pack.prim_object[geom->optix_prim_offset + i] == 0);
- pack.prim_object[geom->optix_prim_offset + i] = ob->get_device_index();
- }
- pack.prim_visibility[geom->optix_prim_offset + i] |= ob->visibility_for_tracing();
- }
- }
}
void BVHOptiX::pack_nodes(const BVHNode *)
diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h
index 3c5a10540d5..4094e173da9 100644
--- a/intern/cycles/kernel/kernel_compat_cuda.h
+++ b/intern/cycles/kernel/kernel_compat_cuda.h
@@ -71,6 +71,7 @@ __device__ half __float2half(const float f)
#define ccl_may_alias
#define ccl_addr_space
#define ccl_restrict __restrict__
+#define ccl_loop_no_unroll
/* TODO(sergey): In theory we might use references with CUDA, however
* performance impact yet to be investigated.
*/
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
index 4963f1cd196..35dc95ca10d 100644
--- a/intern/cycles/kernel/kernel_compat_opencl.h
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -43,6 +43,7 @@
#define ccl_local __local
#define ccl_local_param __local
#define ccl_private __private
+#define ccl_loop_no_unroll __attribute__((opencl_unroll_hint(1)))
#define ccl_restrict restrict
#define ccl_ref
#define ccl_align(n) __attribute__((aligned(n)))
diff --git a/intern/cycles/kernel/kernel_compat_optix.h b/intern/cycles/kernel/kernel_compat_optix.h
index 7068acc3a32..970f5cf864c 100644
--- a/intern/cycles/kernel/kernel_compat_optix.h
+++ b/intern/cycles/kernel/kernel_compat_optix.h
@@ -70,6 +70,7 @@ __device__ half __float2half(const float f)
#define ccl_private
#define ccl_may_alias
#define ccl_addr_space
+#define ccl_loop_no_unroll
#define ccl_restrict __restrict__
#define ccl_ref
#define ccl_align(n) __align__(n)
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 2857de533f3..5292b5f8055 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -1011,7 +1011,13 @@ bool OSLRenderServices::get_userdata(
return false; /* disabled by lockgeom */
}
+#if OSL_LIBRARY_VERSION_CODE >= 11100
+TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename,
+ OSL::ShadingContext *)
+#else
+
TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename)
+#endif
{
OSLTextureHandleMap::iterator it = textures.find(filename);
@@ -1365,6 +1371,17 @@ bool OSLRenderServices::environment(ustring filename,
return status;
}
+#if OSL_LIBRARY_VERSION_CODE >= 11100
+bool OSLRenderServices::get_texture_info(ustring filename,
+ TextureHandle *texture_handle,
+ TexturePerthread *,
+ OSL::ShadingContext *,
+ int subimage,
+ ustring dataname,
+ TypeDesc datatype,
+ void *data,
+ ustring *)
+#else
bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg,
ustring filename,
TextureHandle *texture_handle,
@@ -1372,6 +1389,7 @@ bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg,
ustring dataname,
TypeDesc datatype,
void *data)
+#endif
{
OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
index d32dace23bf..894d6e471ba 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -173,7 +173,12 @@ class OSLRenderServices : public OSL::RendererServices {
void *val,
bool derivatives) override;
+#if OSL_LIBRARY_VERSION_CODE >= 11100
+ TextureSystem::TextureHandle *get_texture_handle(ustring filename,
+ OSL::ShadingContext *context) override;
+#else
TextureSystem::TextureHandle *get_texture_handle(ustring filename) override;
+#endif
bool good(TextureSystem::TextureHandle *texture_handle) override;
@@ -224,6 +229,17 @@ class OSLRenderServices : public OSL::RendererServices {
float *dresultdt,
ustring *errormessage) override;
+#if OSL_LIBRARY_VERSION_CODE >= 11100
+ bool get_texture_info(ustring filename,
+ TextureHandle *texture_handle,
+ TexturePerthread *texture_thread_info,
+ OSL::ShadingContext *shading_context,
+ int subimage,
+ ustring dataname,
+ TypeDesc datatype,
+ void *data,
+ ustring *errormessage) override;
+#else
bool get_texture_info(OSL::ShaderGlobals *sg,
ustring filename,
TextureHandle *texture_handle,
@@ -231,6 +247,7 @@ class OSLRenderServices : public OSL::RendererServices {
ustring dataname,
TypeDesc datatype,
void *data) override;
+#endif
static bool get_background_attribute(
KernelGlobals *kg, ShaderData *sd, ustring name, TypeDesc type, bool derivatives, void *val);
diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h
index 2ad22592eef..f0fc0068fa2 100644
--- a/intern/cycles/kernel/svm/svm_voronoi.h
+++ b/intern/cycles/kernel/svm/svm_voronoi.h
@@ -684,7 +684,8 @@ ccl_device void voronoi_f1_4d(float4 coord,
float4 targetPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
for (int i = -1; i <= 1; i++) {
float4 cellOffset = make_float4(i, j, k, u);
float4 pointPosition = cellOffset +
@@ -722,7 +723,8 @@ ccl_device void voronoi_smooth_f1_4d(float4 coord,
float4 smoothPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
for (int u = -2; u <= 2; u++) {
for (int k = -2; k <= 2; k++) {
- for (int j = -2; j <= 2; j++) {
+ ccl_loop_no_unroll for (int j = -2; j <= 2; j++)
+ {
for (int i = -2; i <= 2; i++) {
float4 cellOffset = make_float4(i, j, k, u);
float4 pointPosition = cellOffset +
@@ -765,7 +767,8 @@ ccl_device void voronoi_f2_4d(float4 coord,
float4 positionF2 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
for (int i = -1; i <= 1; i++) {
float4 cellOffset = make_float4(i, j, k, u);
float4 pointPosition = cellOffset +
@@ -803,7 +806,8 @@ ccl_device void voronoi_distance_to_edge_4d(float4 coord, float randomness, floa
float minDistance = 8.0f;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
for (int i = -1; i <= 1; i++) {
float4 cellOffset = make_float4(i, j, k, u);
float4 vectorToPoint = cellOffset +
@@ -822,7 +826,8 @@ ccl_device void voronoi_distance_to_edge_4d(float4 coord, float randomness, floa
minDistance = 8.0f;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
for (int i = -1; i <= 1; i++) {
float4 cellOffset = make_float4(i, j, k, u);
float4 vectorToPoint = cellOffset +
@@ -851,7 +856,8 @@ ccl_device void voronoi_n_sphere_radius_4d(float4 coord, float randomness, float
float minDistance = 8.0f;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
for (int i = -1; i <= 1; i++) {
float4 cellOffset = make_float4(i, j, k, u);
float4 pointPosition = cellOffset +
@@ -871,7 +877,8 @@ ccl_device void voronoi_n_sphere_radius_4d(float4 coord, float randomness, float
float4 closestPointToClosestPoint = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
for (int i = -1; i <= 1; i++) {
if (i == 0 && j == 0 && k == 0 && u == 0) {
continue;
diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp
index 74b8fc9e5ba..607363d01c6 100644
--- a/intern/cycles/render/mesh_volume.cpp
+++ b/intern/cycles/render/mesh_volume.cpp
@@ -19,6 +19,7 @@
#include "render/scene.h"
#include "util/util_foreach.h"
+#include "util/util_hash.h"
#include "util/util_logging.h"
#include "util/util_progress.h"
#include "util/util_types.h"
@@ -447,7 +448,14 @@ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress)
start_point = transform_point(&itfm, start_point);
cell_size = transform_direction(&itfm, cell_size);
- volume_params.start_point = start_point;
+ /* Slightly offset vertex coordinates to avoid overlapping faces with other
+ * volumes or meshes. The proper solution would be to improve intersection in
+ * the kernel to support robust handling of multiple overlapping faces or use
+ * an all-hit intersection similar to shadows. */
+ const float3 face_overlap_avoidance = cell_size * 0.1f *
+ hash_uint_to_float(hash_string(mesh->name.c_str()));
+
+ volume_params.start_point = start_point + face_overlap_avoidance;
volume_params.cell_size = cell_size;
volume_params.pad_size = pad_size;
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 58bcc7ccdfb..f7df81a0601 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -293,14 +293,12 @@ void Session::run_gpu()
* reset and draw in between */
thread_scoped_lock buffers_lock(buffers_mutex);
- /* avoid excessive denoising in viewport after reaching a certain amount of samples */
- bool need_denoise = tile_manager.schedule_denoising || tile_manager.state.sample < 20 ||
- (time_dt() - last_display_time) >= params.progressive_update_timeout;
-
/* update status and timing */
update_status_time();
/* render */
+ bool delayed_denoise = false;
+ const bool need_denoise = render_need_denoise(delayed_denoise);
render(need_denoise);
device->task_wait();
@@ -311,7 +309,7 @@ void Session::run_gpu()
/* update status and timing */
update_status_time();
- gpu_need_display_buffer_update = need_denoise || !params.run_denoising;
+ gpu_need_display_buffer_update = !delayed_denoise;
gpu_draw_ready = true;
progress.set_update();
@@ -477,7 +475,7 @@ void Session::update_tile_sample(RenderTile &rtile)
update_status_time();
}
-void Session::release_tile(RenderTile &rtile)
+void Session::release_tile(RenderTile &rtile, const bool need_denoise)
{
thread_scoped_lock tile_lock(tile_mutex);
@@ -485,7 +483,7 @@ void Session::release_tile(RenderTile &rtile)
bool delete_tile;
- if (tile_manager.finish_tile(rtile.tile_index, delete_tile)) {
+ if (tile_manager.finish_tile(rtile.tile_index, need_denoise, delete_tile)) {
if (write_render_tile_cb && params.progressive_refine == false) {
write_render_tile_cb(rtile);
}
@@ -687,21 +685,19 @@ void Session::run_cpu()
* reset and draw in between */
thread_scoped_lock buffers_lock(buffers_mutex);
- /* avoid excessive denoising in viewport after reaching a certain amount of samples */
- bool need_denoise = tile_manager.schedule_denoising || tile_manager.state.sample < 20 ||
- (time_dt() - last_display_time) >= params.progressive_update_timeout;
-
/* update status and timing */
update_status_time();
/* render */
+ bool delayed_denoise = false;
+ const bool need_denoise = render_need_denoise(delayed_denoise);
render(need_denoise);
/* update status and timing */
update_status_time();
if (!params.background)
- need_copy_to_display_buffer = need_denoise || !params.run_denoising;
+ need_copy_to_display_buffer = !delayed_denoise;
if (!device->error_message().empty())
progress.set_error(device->error_message());
@@ -1083,7 +1079,46 @@ void Session::update_status_time(bool show_pause, bool show_done)
progress.set_status(status, substatus);
}
-void Session::render(bool with_denoising)
+bool Session::render_need_denoise(bool &delayed)
+{
+ delayed = false;
+
+ /* Denoising enabled? */
+ if (!params.run_denoising) {
+ return false;
+ }
+
+ if (params.background) {
+ /* Background render, only denoise when rendering the last sample. */
+ return tile_manager.done();
+ }
+
+ /* Viewport render. */
+
+ /* It can happen that denoising was already enabled, but the scene still needs an update. */
+ if (scene->film->need_update || !scene->film->denoising_data_offset) {
+ return false;
+ }
+
+ /* Do not denoise until the sample at which denoising should start is reached. */
+ if (tile_manager.state.sample < params.denoising_start_sample) {
+ return false;
+ }
+
+ /* Cannot denoise with resolution divider and separate denoising devices.
+ * It breaks the copy in 'MultiDevice::map_neighbor_tiles' (which operates on
+ * the full buffer dimensions and not the scaled ones). */
+ if (!params.device.denoising_devices.empty() && tile_manager.state.resolution_divider > 1) {
+ return false;
+ }
+
+ /* Avoid excessive denoising in viewport after reaching a certain amount of samples. */
+ delayed = (tile_manager.state.sample >= 20 &&
+ (time_dt() - last_display_time) < params.progressive_update_timeout);
+ return !delayed;
+}
+
+void Session::render(bool need_denoise)
{
if (buffers && tile_manager.state.sample == tile_manager.range_start_sample) {
/* Clear buffers. */
@@ -1098,7 +1133,7 @@ void Session::render(bool with_denoising)
DeviceTask task(DeviceTask::RENDER);
task.acquire_tile = function_bind(&Session::acquire_tile, this, _2, _1, _3);
- task.release_tile = function_bind(&Session::release_tile, this, _1);
+ task.release_tile = function_bind(&Session::release_tile, this, _1, need_denoise);
task.map_neighbor_tiles = function_bind(&Session::map_neighbor_tiles, this, _1, _2);
task.unmap_neighbor_tiles = function_bind(&Session::unmap_neighbor_tiles, this, _1, _2);
task.get_cancel = function_bind(&Progress::get_cancel, &this->progress);
@@ -1115,27 +1150,7 @@ void Session::render(bool with_denoising)
/* Acquire render tiles by default. */
task.tile_types = RenderTile::PATH_TRACE;
- with_denoising = params.run_denoising && with_denoising;
- if (with_denoising) {
- /* Do not denoise viewport until the sample at which denoising should start is reached. */
- if (!params.background && tile_manager.state.sample < params.denoising_start_sample) {
- with_denoising = false;
- }
-
- /* Cannot denoise with resolution divider and separate denoising devices.
- * It breaks the copy in 'MultiDevice::map_neighbor_tiles' (which operates on the full buffer
- * dimensions and not the scaled ones). */
- if (!params.device.denoising_devices.empty() && tile_manager.state.resolution_divider > 1) {
- with_denoising = false;
- }
-
- /* It can happen that denoising was already enabled, but the scene still needs an update. */
- if (scene->film->need_update || !scene->film->denoising_data_offset) {
- with_denoising = false;
- }
- }
-
- if (with_denoising) {
+ if (need_denoise) {
task.denoising = params.denoising;
task.pass_stride = scene->film->pass_stride;
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index 61970d87e9c..f06952e8020 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -186,7 +186,7 @@ class Session {
void update_status_time(bool show_pause = false, bool show_done = false);
- void render(bool with_denoising);
+ void render(bool use_denoise);
void copy_to_display_buffer(int sample);
void reset_(BufferParams &params, int samples);
@@ -199,9 +199,11 @@ class Session {
bool draw_gpu(BufferParams &params, DeviceDrawParams &draw_params);
void reset_gpu(BufferParams &params, int samples);
+ bool render_need_denoise(bool &delayed);
+
bool acquire_tile(RenderTile &tile, Device *tile_device, uint tile_types);
void update_tile_sample(RenderTile &tile);
- void release_tile(RenderTile &tile);
+ void release_tile(RenderTile &tile, const bool need_denoise);
void map_neighbor_tiles(RenderTile *tiles, Device *tile_device);
void unmap_neighbor_tiles(RenderTile *tiles, Device *tile_device);
diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp
index 1480b6d1aab..375c9fd8e09 100644
--- a/intern/cycles/render/tile.cpp
+++ b/intern/cycles/render/tile.cpp
@@ -441,13 +441,13 @@ bool TileManager::check_neighbor_state(int index, Tile::State min_state)
/* Returns whether the tile should be written (and freed if no denoising is used) instead of
* updating. */
-bool TileManager::finish_tile(int index, bool &delete_tile)
+bool TileManager::finish_tile(const int index, const bool need_denoise, bool &delete_tile)
{
delete_tile = false;
switch (state.tiles[index].state) {
case Tile::RENDER: {
- if (!schedule_denoising) {
+ if (!(schedule_denoising && need_denoise)) {
state.tiles[index].state = Tile::DONE;
delete_tile = !progressive;
return true;
diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h
index 9fb9c1ca782..4858a275d5c 100644
--- a/intern/cycles/render/tile.h
+++ b/intern/cycles/render/tile.h
@@ -107,7 +107,7 @@ class TileManager {
void set_samples(int num_samples);
bool next();
bool next_tile(Tile *&tile, int device, uint tile_types);
- bool finish_tile(int index, bool &delete_tile);
+ bool finish_tile(const int index, const bool need_denoise, bool &delete_tile);
bool done();
bool has_tiles();
diff --git a/intern/cycles/util/util_defines.h b/intern/cycles/util/util_defines.h
index 24a20a969ab..e8e414587fb 100644
--- a/intern/cycles/util/util_defines.h
+++ b/intern/cycles/util/util_defines.h
@@ -45,6 +45,7 @@
# define ccl_restrict __restrict
# define ccl_ref &
# define ccl_optional_struct_init
+# define ccl_loop_no_unroll
# define __KERNEL_WITH_SSE_ALIGN__
# if defined(_WIN32) && !defined(FREE_WINDOWS)
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 1c95814f0d9..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;
}
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 8c43eca0dc2..dbed7c5ee5f 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -35,6 +35,8 @@
# include "GHOST_ImeWin32.h"
#endif
+#include <vector>
+
#include <wintab.h>
#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR)
#define PACKETMODE PK_BUTTONS
@@ -259,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,
@@ -294,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 2976dd5053f..a70fdbc9888 100644
--- a/intern/libmv/libmv/simple_pipeline/bundle.cc
+++ b/intern/libmv/libmv/simple_pipeline/bundle.cc
@@ -66,6 +66,12 @@ enum {
namespace {
+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.
//
@@ -89,8 +95,6 @@ void ApplyDistortionModelUsingIntrinsicsBlock(
const T& principal_point_x = intrinsics_block[OFFSET_PRINCIPAL_POINT_X];
const T& principal_point_y = intrinsics_block[OFFSET_PRINCIPAL_POINT_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 (invariant_intrinsics->GetDistortionModelType()) {
@@ -127,11 +131,82 @@ void ApplyDistortionModelUsingIntrinsicsBlock(
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).
@@ -191,6 +266,81 @@ struct ReprojectionErrorApplyIntrinsics {
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 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>
+ 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 {
+ // Unpack the intrinsics.
+ const T& focal_length = intrinsics[OFFSET_FOCAL_LENGTH];
+ const T& principal_point_x = intrinsics[OFFSET_PRINCIPAL_POINT_X];
+ const T& principal_point_y = intrinsics[OFFSET_PRINCIPAL_POINT_Y];
+
+ // 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];
+
+ // Compute image space coordinate from normalized.
+ T predicted_x = focal_length * xn + principal_point_x;
+ T predicted_y = focal_length * yn + principal_point_y;
+
+ 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 - observed_undistorted_image_x) * weight_;
+ residuals[1] = (predicted_y - observed_undistorted_image_y) * weight_;
+
+ return true;
+ }
+
+ 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 optimized.
void BundleIntrinsicsLogMessage(const int bundle_intrinsics) {
if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
@@ -421,14 +571,25 @@ void AddResidualBlockToProblem(const CameraIntrinsics *invariant_intrinsics,
double *camera_R_t,
EuclideanPoint *point,
ceres::Problem* problem) {
- AddResidualBlockToProblemImpl<ReprojectionErrorApplyIntrinsics>(
- invariant_intrinsics,
- marker.x, marker.y,
- marker_weight,
- intrinsics_block,
- camera_R_t,
- point,
- 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
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..d59c7464934 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,234 @@ 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)
+void MANTA::initializeRNAMap(FluidModifierData *mmd)
{
- std::ostringstream ss;
- bool is2D = false;
- int tmpVar;
- float tmpFloat;
+ if (with_debug)
+ cout << "MANTA::initializeRNAMap()" << endl;
- if (varName == "ID") {
- ss << mCurrentID;
- return ss.str();
- }
+ 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);
+
+ int openDomain = (FLUID_DOMAIN_BORDER_BACK | FLUID_DOMAIN_BORDER_FRONT |
+ FLUID_DOMAIN_BORDER_LEFT | FLUID_DOMAIN_BORDER_RIGHT |
+ FLUID_DOMAIN_BORDER_BOTTOM | FLUID_DOMAIN_BORDER_TOP);
+
+ 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);
+
+ mRNAMap["USING_SMOKE"] = to_string((mds->type == FLUID_DOMAIN_TYPE_GAS) != 0);
+ mRNAMap["USING_LIQUID"] = to_string((mds->type == FLUID_DOMAIN_TYPE_LIQUID) != 0);
+ mRNAMap["USING_COLORS"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) != 0);
+ mRNAMap["USING_HEAT"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) != 0);
+ mRNAMap["USING_FIRE"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) != 0);
+ mRNAMap["USING_NOISE"] = to_string((mds->flags & FLUID_DOMAIN_USE_NOISE) != 0);
+ mRNAMap["USING_OBSTACLE"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) != 0);
+ mRNAMap["USING_GUIDING"] = to_string((mds->flags & FLUID_DOMAIN_USE_GUIDE) != 0);
+ mRNAMap["USING_INVEL"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL) != 0);
+ mRNAMap["USING_OUTFLOW"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) != 0);
+ mRNAMap["USING_LOG_DISSOLVE"] = to_string((mds->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG) != 0);
+ mRNAMap["USING_DISSOLVE"] = to_string((mds->flags & FLUID_DOMAIN_USE_DISSOLVE) != 0);
+ mRNAMap["SOLVER_DIM"] = to_string(mds->solver_res);
+ mRNAMap["DO_OPEN"] = to_string(((mds->border_collisions & openDomain) == openDomain) == 0);
+ 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["USING_MESH"] = to_string((mds->flags & FLUID_DOMAIN_USE_MESH) != 0);
+ mRNAMap["USING_IMPROVED_MESH"] = to_string((mds->mesh_generator == FLUID_DOMAIN_MESH_IMPROVED) !=
+ 0);
+ 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_BOUNDARY_DELETE"] = to_string(
+ (mds->sndparticle_boundary == SNDPARTICLE_BOUNDARY_DELETE) != 0);
+ mRNAMap["SNDPARTICLE_BOUNDARY_PUSHOUT"] = to_string(
+ (mds->sndparticle_boundary == SNDPARTICLE_BOUNDARY_PUSHOUT) != 0);
+ 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(mds->viscosity_base *
+ pow(10.0f, -mds->viscosity_exponent));
+ mRNAMap["FLUID_DOMAIN_SIZE"] = to_string(
+ MAX3(mds->global_size[0], mds->global_size[1], mds->global_size[2]));
+ mRNAMap["SNDPARTICLE_TYPES"] = particleTypesStr;
+ mRNAMap["USING_SNDPARTS"] = to_string((mds->particle_type & particleTypes) != 0);
+ 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;
+ mRNAMap["CACHE_RESUMABLE"] = to_string((mds->cache_type == FLUID_DOMAIN_CACHE_FINAL) == 0);
+ mRNAMap["USING_ADAPTIVETIME"] = to_string((mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME) != 0);
+ mRNAMap["USING_SPEEDVECTORS"] = to_string((mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) != 0);
+ mRNAMap["USING_FRACTIONS"] = to_string((mds->flags & FLUID_DOMAIN_USE_FRACTIONS) != 0);
+ mRNAMap["DELETE_IN_OBSTACLE"] = to_string((mds->flags & FLUID_DOMAIN_DELETE_IN_OBSTACLE) != 0);
+ mRNAMap["USING_DIFFUSION"] = to_string((mds->flags & FLUID_DOMAIN_USE_DIFFUSION) != 0);
+}
+
+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 +861,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 +869,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 +891,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 +911,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 +934,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 +957,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 +982,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 +1003,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 +1033,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 +1123,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 +1204,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 +1220,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 +1258,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 +1294,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 +1318,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 +1358,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 +1404,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 +1437,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 +1475,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 +1507,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 +1545,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 +1582,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 +1617,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 +1650,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 +1688,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 +1719,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 +1750,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 +1766,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 +1847,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 +1859,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 +1875,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 +1956,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 +1972,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 +2031,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 +2079,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 +2091,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 +2109,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 +2120,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 +2136,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 +2163,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 +2191,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 +2204,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 +2217,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 +2243,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 +2256,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 +2269,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 +2297,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 +2310,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 +2322,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 +2352,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 +2376,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 +2411,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 +2422,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 +2430,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 +2452,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 +2478,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 +2490,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 +2533,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 +2576,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 +2616,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 +2629,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 +2656,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 +2670,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 +2695,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 +2708,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 +2718,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 +2746,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 +2774,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 +2821,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 +2837,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 +2854,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 +2887,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 +2908,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 +2921,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 +3026,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 +3059,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 +3081,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 +3096,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 +3111,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..3aedde6753f 100644
--- a/intern/mantaflow/intern/strings/liquid_script.h
+++ b/intern/mantaflow/intern/strings/liquid_script.h
@@ -67,8 +67,7 @@ lMax_sp$ID$ = $SNDPARTICLE_L_MAX$\n\
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";
+update_radius_sp$ID$ = $SNDPARTICLE_UPDATE_RADIUS$\n";
//////////////////////////////////////////////////////////////////////
// GRIDS & MESH & PARTICLESYSTEM
@@ -263,7 +262,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,7 +370,7 @@ 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\
diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h
index 146106fd147..ea2b1e9d848 100644
--- a/intern/mantaflow/intern/strings/smoke_script.h
+++ b/intern/mantaflow/intern/strings/smoke_script.h
@@ -302,6 +302,9 @@ def smoke_adaptive_step_$ID$(framenr):\n\
setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, phiIn=phiIn_s$ID$, boundaryWidth=1)\n\
flags_s$ID$.fillGrid()\n\
\n\
+ # reset emission accumulation at the beginning of an adaptive frame\n\
+ if not s$ID$.timePerFrame:\n\
+ emission_s$ID$.setConst(0.)\n\
# accumulate emission value per adaptive step for later use in noise computation\n\
emission_s$ID$.join(emissionIn_s$ID$)\n\
\n\
@@ -373,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/CMakeLists.txt b/intern/string/CMakeLists.txt
deleted file mode 100644
index 8c400f320ae..00000000000
--- a/intern/string/CMakeLists.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-# ***** END GPL LICENSE BLOCK *****
-
-set(INC
- .
-)
-
-set(INC_SYS
-
-)
-
-set(SRC
- intern/STR_String.cpp
-
- STR_String.h
-)
-
-set(LIB
-)
-
-blender_add_lib(bf_intern_string "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
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/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index c736f78d501..c233681dc41 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -377,7 +377,6 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"normal",
"right",
"the lazy dog",
- "trunc(A)",
"unable to load movie clip",
"unable to load text",
"unable to open the file",
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 09e9556cf2c..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
@@ -3859,7 +3861,8 @@ def km_pose(params):
{"properties": [("direction", 'CHILD'), ("extend", False)]}),
("pose.select_hierarchy", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "shift": True},
{"properties": [("direction", 'CHILD'), ("extend", True)]}),
- ("pose.select_linked", {"type": 'L', "value": 'PRESS'}, None),
+ ("pose.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
+ ("pose.select_linked_pick", {"type": 'L', "value": 'PRESS'}, None),
("pose.select_grouped", {"type": 'G', "value": 'PRESS', "shift": True}, None),
("pose.select_mirror", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("pose.constraint_add_with_targets", {"type": 'C', "value": 'PRESS', "shift": True, "ctrl": True}, None),
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 38070d1c400..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'}),
])
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index f900b0ee3df..9e2ce8b83ad 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -87,8 +87,10 @@ def context_path_validate(context, data_path):
# One of the items in the rna path is None, just ignore this
value = Ellipsis
else:
- # We have a real error in the rna path, don't ignore that
- raise
+ # Print invalid path, but don't show error to the users and fully
+ # break the UI if the operator is bound to an event like left click.
+ print("context_path_validate error: context.%s not found (invalid keymap entry?)" % data_path)
+ value = Ellipsis
return value
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index df6281646b4..9efb2e693ee 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")
@@ -1985,7 +1994,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "mode")
if md.mode in {'STROKE', 'STROKE_AND_FILL'}:
- col.label(text="Stroke Texture Control:")
+ col.label(text="Stroke Texture:")
col.prop(md, "fit_method")
col.prop(md, "uv_offset")
col.prop(md, "uv_scale")
@@ -1994,7 +2003,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
col.separator()
if md.mode in {'FILL', 'STROKE_AND_FILL'}:
- col.label(text="Fill Texture Control:")
+ 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")
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 0f6a51ad2d0..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"
@@ -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_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
index d6d2526384a..de526506f68 100644
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py
@@ -1002,7 +1002,6 @@ class PHYSICS_PT_diffusion(PhysicButtonsPanel, Panel):
col.prop(domain, "viscosity_exponent", text="Exponent", slider=True)
col = flow.column()
- col.prop(domain, "domain_size", text="Real World Size")
col.prop(domain, "surface_tension", text="Surface Tension")
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_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_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 e4539ec7ca7..e1f675871ef 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -1139,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:
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 6c769e3b013..3e4a3f5de4c 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1469,6 +1469,7 @@ class VIEW3D_MT_select_pose(Menu):
layout.separator()
layout.operator("pose.select_constraint_target", text="Constraint Target")
+ layout.operator("pose.select_linked", text="Linked")
layout.separator()
@@ -7059,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'
@@ -7132,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/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_curve.h b/source/blender/blenkernel/BKE_curve.h
index adc94a833c3..3524be99d0a 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -111,7 +111,7 @@ 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, bool set);
+void BKE_curve_smooth_flag_set(struct Curve *cu, const bool use_smooth);
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
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_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 2b02895043f..1272127daa0 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -179,6 +179,17 @@ void IDP_Reset(IDProperty *prop, const IDProperty *reference);
# define IDP_Id(prop) ((ID *)(prop)->data.pointer)
#endif
+/**
+ * Call a callback for each idproperty in the hierarchy under given root one (included).
+ *
+ */
+typedef void (*IDPForeachPropertyCallback)(IDProperty *id_property, void *user_data);
+
+void IDP_foreach_property(struct IDProperty *id_property_root,
+ const int type_filter,
+ IDPForeachPropertyCallback callback,
+ void *user_data);
+
/* Format IDProperty as strings */
char *IDP_reprN(const struct IDProperty *prop, uint *r_len);
void IDP_repr_fn(const IDProperty *prop,
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_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 10175a2c45f..7c77d57bc69 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1276,7 +1276,7 @@ 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,
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_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/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index bdf8778651d..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
@@ -300,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
@@ -398,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 f67e49aef06..b8226c57f80 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -901,7 +901,7 @@ 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;
@@ -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;
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index f77e2ea1e0d..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"
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 2cc1d869e4c..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)
{
@@ -344,7 +344,8 @@ typedef enum eGPCurveMappingPreset {
GPCURVE_PRESET_INK = 1,
GPCURVE_PRESET_INKNOISE = 2,
GPCURVE_PRESET_MARKER = 3,
- GPCURVE_PRESET_CHISEL = 4,
+ GPCURVE_PRESET_CHISEL_SENSIVITY = 4,
+ GPCURVE_PRESET_CHISEL_STRENGTH = 5,
} eGPCurveMappingPreset;
static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
@@ -391,11 +392,25 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
cuma->curve[3].x = 1.0f;
cuma->curve[3].y = 1.0f;
break;
- case GPCURVE_PRESET_CHISEL:
+ case GPCURVE_PRESET_CHISEL_SENSIVITY:
cuma->curve[0].x = 0.0f;
cuma->curve[0].y = 0.0f;
- cuma->curve[1].x = 0.8f;
- cuma->curve[1].y = 1.0f;
+ cuma->curve[1].x = 0.25f;
+ cuma->curve[1].y = 0.40f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_CHISEL_STRENGTH:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.31f;
+ cuma->curve[1].y = 0.22f;
+ cuma->curve[2].x = 0.61f;
+ cuma->curve[2].y = 0.88f;
+ cuma->curve[3].x = 1.0f;
+ cuma->curve[3].y = 1.0f;
+ break;
+ default:
break;
}
@@ -587,9 +602,9 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->input_samples = 10;
- brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH;
- brush->gpencil_settings->draw_angle = DEG2RAD(20.0f);
- brush->gpencil_settings->draw_angle_factor = 1.0f;
+ brush->gpencil_settings->active_smooth = 0.3f;
+ brush->gpencil_settings->draw_angle = DEG2RAD(35.0f);
+ brush->gpencil_settings->draw_angle_factor = 0.5f;
brush->gpencil_settings->hardeness = 1.0f;
copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f);
@@ -608,7 +623,12 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_initialize(custom_curve);
- brush_gpencil_curvemap_reset(custom_curve->cm, 2, GPCURVE_PRESET_CHISEL);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_CHISEL_SENSIVITY);
+
+ custom_curve = brush->gpencil_settings->curve_strength;
+ BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ BKE_curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_CHISEL_STRENGTH);
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
@@ -1552,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;
@@ -1583,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;
@@ -1640,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;
@@ -1698,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;
@@ -1755,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);
@@ -2060,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;
@@ -2078,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/constraint.c b/source/blender/blenkernel/intern/constraint.c
index d7bc7b41ca5..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"
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/displist.c b/source/blender/blenkernel/intern/displist.c
index a18579f9402..d35dc32738b 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -848,7 +848,8 @@ static ModifierData *curve_get_tessellate_point(Scene *scene,
return pretessellatePoint;
}
-static void curve_calc_modifiers_pre(
+/* Return true if any modifier was applied. */
+static bool curve_calc_modifiers_pre(
Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb, const bool for_render)
{
VirtualModifierData virtualModifierData;
@@ -861,6 +862,7 @@ static void curve_calc_modifiers_pre(
float(*deformedVerts)[3] = NULL;
float *keyVerts = NULL;
int required_mode;
+ bool modified = false;
modifiers_clearErrors(ob);
@@ -913,6 +915,7 @@ static void curve_calc_modifiers_pre(
}
mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
+ modified = true;
if (md == pretessellatePoint) {
break;
@@ -931,6 +934,7 @@ static void curve_calc_modifiers_pre(
if (keyVerts) {
MEM_freeN(keyVerts);
}
+ return modified;
}
static float (*displist_vert_coords_alloc(ListBase *dispbase, int *r_vert_len))[3]
@@ -974,7 +978,8 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
ListBase *nurb,
ListBase *dispbase,
Mesh **r_final,
- const bool for_render)
+ const bool for_render,
+ const bool force_mesh_conversion)
{
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
@@ -1128,6 +1133,22 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
}
if (r_final) {
+ if (force_mesh_conversion && !modified) {
+ /* XXX 2.8 : This is a workaround for by some deeper technical depts:
+ * - DRW Batch cache is stored inside the ob->data.
+ * - Curve data is not COWed for instances that use different modifiers.
+ * This can causes the modifiers to be applied on all user of the same datablock (see T71055)
+ *
+ * The easy workaround is to force to generate a Mesh that will be used for display data
+ * since a Mesh output is already used for generative modifiers.
+ * However it does not fix problems with actual edit data still being shared.
+ *
+ * The right solution would be to COW the Curve data block at the input of the modifer stack
+ * just like what the mesh modifier does.
+ * */
+ modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
+ }
+
if (modified) {
/* XXX2.8(Sybren): make sure the face normals are recalculated as well */
@@ -1202,6 +1223,7 @@ void BKE_displist_make_surf(Depsgraph *depsgraph,
DispList *dl;
float *data;
int len;
+ bool force_mesh_conversion = false;
if (!for_render && cu->editnurb) {
BKE_nurbList_duplicate(&nubase, BKE_curve_editNurbs_get(cu));
@@ -1211,7 +1233,7 @@ void BKE_displist_make_surf(Depsgraph *depsgraph,
}
if (!for_orco) {
- curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render);
+ force_mesh_conversion = curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render);
}
for (nu = nubase.first; nu; nu = nu->next) {
@@ -1289,7 +1311,8 @@ void BKE_displist_make_surf(Depsgraph *depsgraph,
if (!for_orco) {
BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render);
+ curve_calc_modifiers_post(
+ depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, force_mesh_conversion);
}
BKE_nurbList_free(&nubase);
@@ -1537,6 +1560,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
ListBase dlbev;
ListBase nubase = {NULL, NULL};
+ bool force_mesh_conversion = false;
BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
@@ -1559,7 +1583,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
}
if (!for_orco) {
- curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render);
+ force_mesh_conversion = curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render);
}
BKE_curve_bevelList_make(ob, &nubase, for_render);
@@ -1769,7 +1793,8 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
if (!for_orco) {
BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render);
+ curve_calc_modifiers_post(
+ depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, force_mesh_conversion);
}
if (cu->flag & CU_DEFORM_FILL && !ob->runtime.data_eval) {
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..3f55831cfeb 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,325 @@ 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];
+ }
+}
+
+/* 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);
}
- /* return value */
- return cvalue;
+ 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 d4f54daa773..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. */
@@ -4889,7 +4873,6 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
mmd->domain->surface_tension = 0.0f;
mmd->domain->viscosity_base = 1.0f;
mmd->domain->viscosity_exponent = 6.0f;
- mmd->domain->domain_size = 0.5f;
/* mesh options */
mmd->domain->mesh_velocities = NULL;
@@ -5133,7 +5116,6 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd,
tmds->surface_tension = mds->surface_tension;
tmds->viscosity_base = mds->viscosity_base;
tmds->viscosity_exponent = mds->viscosity_exponent;
- tmds->domain_size = mds->domain_size;
/* mesh options */
if (mds->mesh_velocities) {
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index 874672f4a73..413e28c431b 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -1710,7 +1710,7 @@ static void gpencil_convert_spline(Main *bmain,
/* Create Stroke. */
bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
- gps->thickness = 1.0f;
+ gps->thickness = 10.0f;
gps->fill_opacity_fac = 1.0f;
gps->hardeness = 1.0f;
gps->uv_scale = 1.0f;
@@ -1731,7 +1731,7 @@ static void gpencil_convert_spline(Main *bmain,
int segments = 0;
int resolu = nu->resolu + 1;
segments = nu->pntsu;
- if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
+ if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
segments--;
cyclic = false;
}
@@ -1847,7 +1847,7 @@ static void gpencil_convert_spline(Main *bmain,
int init = 0;
resolu = nu->resolu + 1;
segments = nu->pntsu;
- if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
+ if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
segments--;
}
/* Get all interpolated curve points of Beziert */
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 5530a126ffc..669539ca574 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -1130,4 +1130,45 @@ void IDP_Reset(IDProperty *prop, const IDProperty *reference)
}
}
+/**
+ * Loop through all ID properties in hierarchy of given \a id_property_root included.
+ *
+ * \note Container types (groups and arrays) are processed after applying the callback on them.
+ *
+ * \param type_filter: If not 0, only apply callback on properties of matching types, see
+ * IDP_TYPE_FILTER_ enum in DNA_ID.h.
+ */
+void IDP_foreach_property(IDProperty *id_property_root,
+ const int type_filter,
+ IDPForeachPropertyCallback callback,
+ void *user_data)
+{
+ if (!id_property_root) {
+ return;
+ }
+
+ if (type_filter == 0 || (1 << id_property_root->type) & type_filter) {
+ callback(id_property_root, user_data);
+ }
+
+ /* Recursive call into container types of ID properties. */
+ switch (id_property_root->type) {
+ case IDP_GROUP: {
+ LISTBASE_FOREACH (IDProperty *, loop, &id_property_root->data.group) {
+ IDP_foreach_property(loop, type_filter, callback, user_data);
+ }
+ break;
+ }
+ case IDP_IDPARRAY: {
+ IDProperty *loop = IDP_Array(id_property_root);
+ for (int i = 0; i < id_property_root->len; i++) {
+ IDP_foreach_property(&loop[i], type_filter, callback, user_data);
+ }
+ break;
+ }
+ default:
+ break; /* Nothing to do here with other types of IDProperties... */
+ }
+}
+
/** \} */
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/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index bddf8c0f819..31ac8ca623b 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -68,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"
@@ -173,41 +173,20 @@ static void library_foreach_ID_link(Main *bmain,
int flag,
LibraryForeachIDData *inherit_data);
-static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data,
- IDProperty *prop,
- int flag)
+static void library_foreach_idpropertiesForeachIDLink(IDProperty *id_prop, void *user_data)
{
- if (!prop) {
- return;
- }
+ BLI_assert(id_prop->type == IDP_ID);
- switch (prop->type) {
- case IDP_GROUP: {
- LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
- library_foreach_idproperty_ID_link(data, loop, flag);
- }
- break;
- }
- case IDP_IDPARRAY: {
- IDProperty *loop = IDP_Array(prop);
- for (int i = 0; i < prop->len; i++) {
- library_foreach_idproperty_ID_link(data, &loop[i], flag);
- }
- break;
- }
- case IDP_ID:
- FOREACH_CALLBACK_INVOKE_ID(data, prop->data.pointer, flag);
- break;
- default:
- break; /* Nothing to do here with other types of IDProperties... */
- }
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ FOREACH_CALLBACK_INVOKE_ID(data, id_prop->data.pointer, IDWALK_CB_USER);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock)
{
- library_foreach_idproperty_ID_link(data, sock->prop, IDWALK_CB_USER);
+ IDP_foreach_property(
+ sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
@@ -308,11 +287,9 @@ static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(p
static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip)
{
- NlaStrip *substrip;
-
FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER);
- for (substrip = strip->strips.first; substrip; substrip = substrip->next) {
+ LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) {
library_foreach_nla_strip(data, substrip);
}
@@ -321,15 +298,10 @@ static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *stri
static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt)
{
- FCurve *fcu;
- NlaTrack *nla_track;
- NlaStrip *nla_strip;
-
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
/* only used targets */
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP);
@@ -341,8 +313,8 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER);
FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_USER);
- for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) {
- for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) {
+ LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) {
+ LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) {
library_foreach_nla_strip(data, nla_strip);
}
}
@@ -371,7 +343,8 @@ static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone)
{
- library_foreach_idproperty_ID_link(data, bone->prop, IDWALK_CB_USER);
+ IDP_foreach_property(
+ bone->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, data);
LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) {
library_foreach_bone(data, curbone);
@@ -518,7 +491,6 @@ static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *are
}
case SPACE_NODE: {
SpaceNode *snode = (SpaceNode *)sl;
- bNodeTreePath *path;
const bool is_private_nodetree = snode->id != NULL &&
ntreeFromID(snode->id) == snode->nodetree;
@@ -529,7 +501,7 @@ static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *are
FOREACH_CALLBACK_INVOKE(
data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE);
- for (path = snode->treepath.first; path; path = path->next) {
+ LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
if (path == snode->treepath.first) {
/* first nodetree in path is same as snode->nodetree */
FOREACH_CALLBACK_INVOKE(data,
@@ -563,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);
@@ -587,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;
@@ -677,7 +648,8 @@ static void library_foreach_ID_link(Main *bmain,
IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE);
}
- library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER);
+ IDP_foreach_property(
+ id->properties, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
@@ -702,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;
@@ -713,7 +684,8 @@ static void library_foreach_ID_link(Main *bmain,
CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER);
CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER);
CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER);
- library_foreach_idproperty_ID_link(&data, seq->prop, IDWALK_CB_USER);
+ IDP_foreach_property(
+ seq->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) {
CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER);
}
@@ -731,8 +703,7 @@ static void library_foreach_ID_link(Main *bmain,
library_foreach_collection(&data, scene->master_collection);
}
- ViewLayer *view_layer;
- for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
CALLBACK_INVOKE(view_layer->mat_override, IDWALK_CB_USER);
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
@@ -811,7 +782,6 @@ static void library_foreach_ID_link(Main *bmain,
case ID_OB: {
Object *object = (Object *)id;
- ParticleSystem *psys;
/* Object is special, proxies make things hard... */
const int data_cb_flag = data.cb_flag;
@@ -867,11 +837,10 @@ static void library_foreach_ID_link(Main *bmain,
/* Note that ob->effect is deprecated, so no need to handle it here. */
if (object->pose) {
- bPoseChannel *pchan;
-
data.cb_flag |= proxy_cb_flag;
- for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
- library_foreach_idproperty_ID_link(&data, pchan->prop, IDWALK_CB_USER);
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ IDP_foreach_property(
+ pchan->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER);
BKE_constraints_id_loop(
&pchan->constraints, library_foreach_constraintObjectLooper, &data);
@@ -885,8 +854,7 @@ static void library_foreach_ID_link(Main *bmain,
}
if (object->lodlevels.first) {
- LodLevel *level;
- for (level = object->lodlevels.first; level; level = level->next) {
+ LISTBASE_FOREACH (LodLevel *, level, &object->lodlevels) {
CALLBACK_INVOKE(level->source, IDWALK_CB_NEVER_SELF);
}
}
@@ -898,7 +866,7 @@ static void library_foreach_ID_link(Main *bmain,
&object->constraints, library_foreach_constraintObjectLooper, &data);
BKE_shaderfx_foreachIDLink(object, library_foreach_shaderfxForeachIDLink, &data);
- for (psys = object->particlesystem.first; psys; psys = psys->next) {
+ LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
}
@@ -959,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);
@@ -976,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;
@@ -993,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;
}
@@ -1024,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;
}
@@ -1051,14 +1015,14 @@ static void library_foreach_ID_link(Main *bmain,
case ID_NT: {
bNodeTree *ntree = (bNodeTree *)id;
- bNode *node;
CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER);
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER);
- library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER);
+ IDP_foreach_property(
+ node->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data);
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
library_foreach_node_socket(&data, sock);
}
@@ -1116,11 +1080,8 @@ static void library_foreach_ID_link(Main *bmain,
}
if (psett->boids) {
- BoidState *state;
- BoidRule *rule;
-
- for (state = psett->boids->states.first; state; state = state->next) {
- for (rule = state->rules.first; rule; rule = rule->next) {
+ LISTBASE_FOREACH (BoidState *, state, &psett->boids->states) {
+ LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
if (rule->type == eBoidRuleType_Avoid) {
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP);
@@ -1142,23 +1103,19 @@ static void library_foreach_ID_link(Main *bmain,
case ID_MC: {
MovieClip *clip = (MovieClip *)id;
MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
CALLBACK_INVOKE(clip->gpd, IDWALK_CB_USER);
- for (track = tracking->tracks.first; track; track = track->next) {
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
}
- for (object = tracking->objects.first; object; object = object->next) {
- for (track = object->tracks.first; track; track = track->next) {
+ LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, &object->tracks) {
CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
}
}
- for (plane_track = tracking->plane_tracks.first; plane_track;
- plane_track = plane_track->next) {
+ LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking->plane_tracks) {
CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER);
}
break;
@@ -1166,12 +1123,9 @@ static void library_foreach_ID_link(Main *bmain,
case ID_MSK: {
Mask *mask = (Mask *)id;
- MaskLayer *mask_layer;
- for (mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- MaskSpline *mask_spline;
- for (mask_spline = mask_layer->splines.first; mask_spline;
- mask_spline = mask_spline->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
+ LISTBASE_FOREACH (MaskSpline *, mask_spline, &mask_layer->splines) {
for (i = 0; i < mask_spline->tot_point; i++) {
MaskSplinePoint *point = &mask_spline->points[i];
CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER);
@@ -1183,7 +1137,7 @@ static void library_foreach_ID_link(Main *bmain,
case ID_LS: {
FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
- LineStyleModifier *lsm;
+
for (i = 0; i < MAX_MTEX; i++) {
if (linestyle->mtex[i]) {
library_foreach_mtex(&data, linestyle->mtex[i]);
@@ -1191,11 +1145,10 @@ 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);
}
- for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
+ LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) {
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleColorModifier_DistanceFromObject *p =
(LineStyleColorModifier_DistanceFromObject *)lsm;
@@ -1204,7 +1157,7 @@ static void library_foreach_ID_link(Main *bmain,
}
}
}
- for (lsm = linestyle->alpha_modifiers.first; lsm; lsm = lsm->next) {
+ LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->alpha_modifiers) {
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleAlphaModifier_DistanceFromObject *p =
(LineStyleAlphaModifier_DistanceFromObject *)lsm;
@@ -1213,7 +1166,7 @@ static void library_foreach_ID_link(Main *bmain,
}
}
}
- for (lsm = linestyle->thickness_modifiers.first; lsm; lsm = lsm->next) {
+ LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->thickness_modifiers) {
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleThicknessModifier_DistanceFromObject *p =
(LineStyleThicknessModifier_DistanceFromObject *)lsm;
@@ -1280,8 +1233,7 @@ static void library_foreach_ID_link(Main *bmain,
CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER);
}
- for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL;
- gplayer = gplayer->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) {
CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP);
}
@@ -1323,8 +1275,7 @@ static void library_foreach_ID_link(Main *bmain,
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, callback, user_data, flag, &data);
+ library_foreach_ID_as_subdata_link((ID **)&simulation->nodetree, &data);
}
break;
}
@@ -1382,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. */
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 78991ad063d..f0d19f01aab 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -1300,7 +1300,7 @@ 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_user_data(pool);
LoopSplitTaskData *data = taskdata;
@@ -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/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 7991559d1ce..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 {
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 6dc03c518fe..d79dbbb7d32 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -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/object.c b/source/blender/blenkernel/intern/object.c
index a12307b7c18..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"
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 4835a4c6a62..8957628c76a 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -453,9 +453,7 @@ 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_user_data(pool);
const Ocean *o = osd->o;
@@ -463,9 +461,7 @@ static void ocean_compute_displacement_y(TaskPool *__restrict pool,
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_user_data(pool);
const Ocean *o = osd->o;
@@ -494,9 +490,7 @@ 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_user_data(pool);
const Ocean *o = osd->o;
@@ -525,9 +519,7 @@ 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_user_data(pool);
const Ocean *o = osd->o;
@@ -560,9 +552,7 @@ 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_user_data(pool);
const Ocean *o = osd->o;
@@ -595,9 +585,7 @@ 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_user_data(pool);
const Ocean *o = osd->o;
@@ -624,9 +612,7 @@ 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_user_data(pool);
const Ocean *o = osd->o;
@@ -645,9 +631,7 @@ 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_user_data(pool);
const Ocean *o = osd->o;
@@ -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/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/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index f999a98faac..a08bbf182fa 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -1225,6 +1225,10 @@ struct ImBuf *BKE_sequencer_cache_get(
seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
}
+ if (!seq) {
+ return NULL;
+ }
+
if (!scene->ed->cache) {
seq_cache_create(context->bmain, scene);
}
@@ -1287,6 +1291,10 @@ bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context,
seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
}
+ if (!seq) {
+ return false;
+ }
+
if (BKE_sequencer_cache_recycle_item(scene)) {
BKE_sequencer_cache_put(context, seq, cfra, type, ibuf, cost, skip_disk_cache);
return true;
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 bba829529a3..1425bff48a8 100644
--- a/source/blender/blenkernel/intern/seqprefetch.c
+++ b/source/blender/blenkernel/intern/seqprefetch.c
@@ -134,19 +134,29 @@ static bool seq_prefetch_job_is_waiting(Scene *scene)
return pfjob->waiting;
}
-/* for cache context swapping */
-Sequence *BKE_sequencer_prefetch_get_original_sequence(Sequence *seq, Scene *scene)
+static Sequence *sequencer_prefetch_get_original_sequence(Sequence *seq, ListBase *seqbase)
{
- Editing *ed = scene->ed;
- ListBase *seqbase = &ed->seqbase;
- Sequence *seq_orig = NULL;
-
- for (seq_orig = (Sequence *)seqbase->first; seq_orig; seq_orig = seq_orig->next) {
+ LISTBASE_FOREACH (Sequence *, seq_orig, seqbase) {
if (strcmp(seq->name, seq_orig->name) == 0) {
- break;
+ return seq_orig;
+ }
+
+ if (seq_orig->type == SEQ_TYPE_META) {
+ Sequence *match = sequencer_prefetch_get_original_sequence(seq, &seq_orig->seqbase);
+ if (match != NULL) {
+ return match;
+ }
}
}
- return seq_orig;
+
+ return NULL;
+}
+
+/* for cache context swapping */
+Sequence *BKE_sequencer_prefetch_get_original_sequence(Sequence *seq, Scene *scene)
+{
+ Editing *ed = scene->ed;
+ return sequencer_prefetch_get_original_sequence(seq, &ed->seqbase);
}
/* for cache context swapping */
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 5136c526416..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 {
@@ -3679,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);
@@ -3723,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;
}
@@ -3931,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 {
@@ -3940,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/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 6637b3e9b69..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;
@@ -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;
@@ -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 0884f40952f..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)
{
@@ -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/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/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh
index 61d57599619..9dd8341aa76 100644
--- a/source/blender/blenlib/BLI_array.hh
+++ b/source/blender/blenlib/BLI_array.hh
@@ -80,7 +80,7 @@ class Array {
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
@@ -202,6 +202,11 @@ class Array {
return IndexRange(m_size);
}
+ Allocator &allocator()
+ {
+ return m_allocator;
+ }
+
private:
T *get_buffer_for_size(uint size)
{
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_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_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_map.hh b/source/blender/blenlib/BLI_map.hh
index 553175b0395..ea5e5da4099 100644
--- a/source/blender/blenlib/BLI_map.hh
+++ b/source/blender/blenlib/BLI_map.hh
@@ -408,6 +408,19 @@ class Map {
}
/**
+ * 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
@@ -416,6 +429,14 @@ class Map {
}
/**
+ * 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
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_open_addressing.hh b/source/blender/blenlib/BLI_open_addressing.hh
index d466a915b2f..3bd932350d0 100644
--- a/source/blender/blenlib/BLI_open_addressing.hh
+++ b/source/blender/blenlib/BLI_open_addressing.hh
@@ -34,6 +34,7 @@
#include <cmath>
#include "BLI_allocator.hh"
+#include "BLI_array.hh"
#include "BLI_math_base.h"
#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
@@ -114,8 +115,6 @@ class OpenAddressingArray {
* 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. */
@@ -130,9 +129,8 @@ 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<(uint)sizeof(Item) * s_items_in_small_storage, (uint)alignof(Item)>
- m_local_storage;
+
+ Array<Item, s_items_in_small_storage, Allocator> m_items;
public:
explicit OpenAddressingArray(uint8_t item_exponent = s_small_storage_item_exponent)
@@ -147,51 +145,12 @@ class OpenAddressingArray {
(uint64_t)s_max_load_factor_numerator,
(uint64_t)s_max_load_factor_denominator);
- if (m_item_amount <= s_items_in_small_storage) {
- 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 <= s_items_in_small_storage) {
- 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
{
@@ -202,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();
}
@@ -237,7 +189,7 @@ class OpenAddressingArray {
Allocator &allocator()
{
- return m_allocator;
+ return m_items.allocator();
}
/* Prepare a new array that can hold a minimum of min_usable_slots elements. All entries are
@@ -340,33 +292,22 @@ 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();
}
};
diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh
index b09dd910007..dc9df5d116a 100644
--- a/source/blender/blenlib/BLI_set.hh
+++ b/source/blender/blenlib/BLI_set.hh
@@ -277,6 +277,20 @@ class Set {
}
/**
+ * Return true if this set contains no elements.
+ */
+ bool is_empty() const
+ {
+ return this->size() == 0;
+ }
+
+ void clear()
+ {
+ this->~Set();
+ new (this) Set();
+ }
+
+ /**
* Returns true when there is at least one element that is in both sets.
* Otherwise false.
*/
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 42dd47266dc..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 (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata);
typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata);
-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);
+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);
@@ -110,36 +97,10 @@ 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.
*/
@@ -163,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).
*/
@@ -199,7 +158,7 @@ void BLI_task_parallel_range(const int start,
const int stop,
void *userdata,
TaskParallelRangeFunc func,
- TaskParallelSettings *settings);
+ const TaskParallelSettings *settings);
/* This data is shared between all tasks, its access needs thread lock or similar protection.
*/
@@ -254,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_vector.hh b/source/blender/blenlib/BLI_vector.hh
index 40dc876d5a5..49cf41c2005 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -427,7 +427,7 @@ class Vector {
/**
* Returns true when the vector contains no elements, otherwise false.
*/
- bool empty() const
+ bool is_empty() const
{
return m_begin == m_end;
}
@@ -438,7 +438,7 @@ class Vector {
*/
void remove_last()
{
- BLI_assert(!this->empty());
+ BLI_assert(!this->is_empty());
m_end--;
destruct(m_end);
UPDATE_VECTOR_SIZE(this);
@@ -449,7 +449,7 @@ class Vector {
*/
T pop_last()
{
- BLI_assert(!this->empty());
+ BLI_assert(!this->is_empty());
m_end--;
T value = std::move(*m_end);
destruct(m_end);
diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh
index 6e1ab823e86..9f887513816 100644
--- a/source/blender/blenlib/BLI_vector_set.hh
+++ b/source/blender/blenlib/BLI_vector_set.hh
@@ -317,6 +317,11 @@ 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;
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 19089447b95..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,8 +119,10 @@ 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
@@ -161,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
@@ -275,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
@@ -282,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/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 1189ec0d0c0..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,82 +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 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;
-
- /* 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,
@@ -154,232 +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_user_data(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;
- const bool use_tls_data = (tls_data_size != 0) && (initial_tls_memory != NULL);
- TaskParallelTLS tls = {
- .thread_id = 0,
- .userdata_chunk = initial_tls_memory,
- };
- for (int i = start; i < stop; i++) {
- func(userdata, i, &tls);
- }
- if (use_tls_data && state->func_free != NULL) {
- /* `func_free` should only free data that was created during execution of `func`. */
- state->func_free(userdata, initial_tls_memory);
- }
- }
-}
-
-/**
- * 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_free = settings->func_free,
- };
- 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 && (settings->func_free != NULL || settings->func_reduce != NULL)) {
- for (i = 0; i < num_tasks; i++) {
- void *userdata_chunk_local = (char *)flatten_tls_storage + (tls_data_size * (size_t)i);
- if (settings->func_reduce) {
- settings->func_reduce(userdata, tls_data, userdata_chunk_local);
- }
- if (settings->func_free) {
- /* `func_free` should only free data that was created during execution of `func`. */
- settings->func_free(userdata, userdata_chunk_local);
- }
- }
- MALLOCA_FREE(flatten_tls_storage, tls_data_size * (size_t)num_tasks);
- }
+ *r_chunk_size = chunk_size;
}
typedef struct TaskParallelIteratorState {
@@ -394,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,
};
@@ -460,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_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,
@@ -483,7 +178,7 @@ 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 && settings->func_free != NULL) {
/* `func_free` should only free data that was created during execution of `func`. */
@@ -494,10 +189,10 @@ static void task_parallel_iterator_no_threads(const TaskParallelSettings *settin
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);
@@ -526,21 +221,19 @@ 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);
@@ -656,7 +349,7 @@ 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_user_data(pool);
BLI_mempool_iter *iter = taskdata;
@@ -684,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;
@@ -704,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
@@ -720,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 60ed156105c..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 UNUSED(thread_id))
-{
- if (task->free_taskdata) {
- if (task->freedata) {
- task->freedata(task->pool, task->taskdata);
- }
- 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,228 +409,114 @@ 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_user_data(TaskPool *pool)
@@ -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/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index ac1d315434d..418750a8df2 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -118,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"
@@ -9715,7 +9715,9 @@ static bool read_libblock_undo_restore(
/* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as
* this is only for do_version-like code), but for sake of consistency, and also because
* it will tell us which ID is re-used from old Main, and which one is actually new. */
- const int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED;
+ /* Also do not add LIB_TAG_NEED_LINK, those IDs will never be re-liblinked, hence that tag will
+ * never be cleared, leading to critical issue in link/appemd code. */
+ const int id_tag = tag | LIB_TAG_UNDO_OLD_ID_REUSED;
read_libblock_undo_restore_identical(fd, main, id, id_old, id_tag);
/* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old).
@@ -10195,6 +10197,15 @@ static void lib_link_all(FileData *fd, Main *bmain)
* 'permanently' in our data structures... */
BKE_main_collections_parent_relations_rebuild(bmain);
}
+
+#ifndef NDEBUG
+ /* Double check we do not have any 'need link' tag remaining, this should never be the case once
+ * this function has run. */
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ BLI_assert((id->tag & LIB_TAG_NEED_LINK) == 0);
+ }
+ FOREACH_MAIN_ID_END;
+#endif
}
/** \} */
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/writefile.c b/source/blender/blenloader/intern/writefile.c
index 9adcceb1b6b..3015a0e1b8a 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -157,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"
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 25037fbd1b5..5ae6201227b 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -75,9 +75,10 @@ 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"
#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_key.h"
@@ -121,20 +122,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 */
@@ -148,15 +135,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);
}
}
@@ -167,7 +157,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;
@@ -183,7 +173,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),
@@ -321,7 +311,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
@@ -345,11 +334,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;
@@ -361,12 +350,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()
@@ -493,6 +481,18 @@ void DepsgraphNodeBuilder::build_id(ID *id)
}
}
+static void build_idproperties_callback(IDProperty *id_property, void *user_data)
+{
+ DepsgraphNodeBuilder *builder = reinterpret_cast<DepsgraphNodeBuilder *>(user_data);
+ BLI_assert(id_property->type == IDP_ID);
+ builder->build_id(reinterpret_cast<ID *>(id_property->data.pointer));
+}
+
+void DepsgraphNodeBuilder::build_idproperties(IDProperty *id_property)
+{
+ IDP_foreach_property(id_property, IDP_TYPE_FILTER_ID, build_idproperties_callback, this);
+}
+
void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collection,
Collection *collection)
{
@@ -521,6 +521,8 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti
/* Collection itself. */
id_node = add_id_node(&collection->id);
id_node->is_directly_visible = is_collection_visible;
+
+ build_idproperties(collection->id.properties);
}
if (from_layer_collection != nullptr) {
/* If we came from layer collection we don't go deeper, view layer
@@ -633,6 +635,7 @@ void DepsgraphNodeBuilder::build_object(int base_index,
/* Parameters, used by both drivers/animation and also to inform dependency
* from object's data. */
build_parameters(&object->id);
+ build_idproperties(object->id.properties);
/* Build animation data,
*
* Do it now because it's possible object data will affect
@@ -947,6 +950,7 @@ void DepsgraphNodeBuilder::build_action(bAction *action)
if (built_map_.checkIsBuiltAndTag(action)) {
return;
}
+ build_idproperties(action->id.properties);
add_operation_node(&action->id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL);
}
@@ -1052,6 +1056,7 @@ void DepsgraphNodeBuilder::build_world(World *world)
NodeType::SHADING,
OperationCode::WORLD_UPDATE,
function_bind(BKE_world_eval, _1, world_cow));
+ build_idproperties(world->id.properties);
/* Animation. */
build_animdata(&world->id);
build_parameters(&world->id);
@@ -1234,6 +1239,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
if (built_map_.checkIsBuiltAndTag(key)) {
return;
}
+ build_idproperties(key->id.properties);
build_animdata(&key->id);
build_parameters(&key->id);
/* This is an exit operation for the entire key datablock, is what is used
@@ -1288,6 +1294,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
/* Make sure we've got an ID node before requesting CoW pointer. */
(void)add_id_node((ID *)obdata);
ID *obdata_cow = get_cow_id(obdata);
+ build_idproperties(obdata->properties);
/* Animation. */
build_animdata(obdata);
/* ShapeKeys */
@@ -1393,10 +1400,20 @@ void DepsgraphNodeBuilder::build_armature(bArmature *armature)
if (built_map_.checkIsBuiltAndTag(armature)) {
return;
}
+ build_idproperties(armature->id.properties);
build_animdata(&armature->id);
build_parameters(&armature->id);
/* Make sure pose is up-to-date with armature updates. */
add_operation_node(&armature->id, NodeType::ARMATURE, OperationCode::ARMATURE_EVAL);
+ build_armature_bones(&armature->bonebase);
+}
+
+void DepsgraphNodeBuilder::build_armature_bones(ListBase *bones)
+{
+ LISTBASE_FOREACH (Bone *, bone, bones) {
+ build_idproperties(bone->prop);
+ build_armature_bones(&bone->childbase);
+ }
}
void DepsgraphNodeBuilder::build_camera(Camera *camera)
@@ -1404,6 +1421,7 @@ void DepsgraphNodeBuilder::build_camera(Camera *camera)
if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
+ build_idproperties(camera->id.properties);
build_animdata(&camera->id);
build_parameters(&camera->id);
if (camera->dof.focus_object != nullptr) {
@@ -1416,6 +1434,7 @@ void DepsgraphNodeBuilder::build_light(Light *lamp)
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
+ build_idproperties(lamp->id.properties);
build_animdata(&lamp->id);
build_parameters(&lamp->id);
/* light's nodetree */
@@ -1435,6 +1454,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
bNodeTree *ntree_cow = get_cow_datablock(ntree);
/* General parameters. */
build_parameters(&ntree->id);
+ build_idproperties(ntree->id.properties);
/* Animation, */
build_animdata(&ntree->id);
/* Shading update. */
@@ -1447,6 +1467,14 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
function_bind(BKE_nodetree_shading_params_eval, _1, ntree_cow, ntree));
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
+ build_idproperties(bnode->prop);
+ LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->inputs) {
+ build_idproperties(socket->prop);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->outputs) {
+ build_idproperties(socket->prop);
+ }
+
ID *id = bnode->id;
if (id == nullptr) {
continue;
@@ -1495,6 +1523,13 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
}
}
+ LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->inputs) {
+ build_idproperties(socket->prop);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->outputs) {
+ build_idproperties(socket->prop);
+ }
+
// TODO: link from nodetree to owner_component?
}
@@ -1512,6 +1547,7 @@ void DepsgraphNodeBuilder::build_material(Material *material)
NodeType::SHADING,
OperationCode::MATERIAL_UPDATE,
function_bind(BKE_material_eval, _1, material_cow));
+ build_idproperties(material->id.properties);
/* Material animation. */
build_animdata(&material->id);
build_parameters(&material->id);
@@ -1536,6 +1572,7 @@ void DepsgraphNodeBuilder::build_texture(Tex *texture)
return;
}
/* Texture itself. */
+ build_idproperties(texture->id.properties);
build_animdata(&texture->id);
build_parameters(&texture->id);
/* Texture's nodetree. */
@@ -1556,6 +1593,7 @@ void DepsgraphNodeBuilder::build_image(Image *image)
return;
}
build_parameters(&image->id);
+ build_idproperties(image->id.properties);
add_operation_node(
&image->id, NodeType::GENERIC_DATABLOCK, OperationCode::GENERIC_DATABLOCK_UPDATE);
}
@@ -1584,6 +1622,7 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
ID *cache_file_id = &cache_file->id;
add_id_node(cache_file_id);
CacheFile *cache_file_cow = get_cow_datablock(cache_file);
+ build_idproperties(cache_file_id->properties);
/* Animation, */
build_animdata(cache_file_id);
build_parameters(cache_file_id);
@@ -1601,6 +1640,7 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask)
}
ID *mask_id = &mask->id;
Mask *mask_cow = (Mask *)ensure_cow_id(mask_id);
+ build_idproperties(mask->id.properties);
/* F-Curve based animation. */
build_animdata(mask_id);
build_parameters(mask_id);
@@ -1637,6 +1677,7 @@ void DepsgraphNodeBuilder::build_freestyle_linestyle(FreestyleLineStyle *linesty
ID *linestyle_id = &linestyle->id;
build_parameters(linestyle_id);
+ build_idproperties(linestyle->id.properties);
build_animdata(linestyle_id);
build_nodetree(linestyle->nodetree);
}
@@ -1648,6 +1689,7 @@ void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip)
}
ID *clip_id = &clip->id;
MovieClip *clip_cow = (MovieClip *)ensure_cow_id(clip_id);
+ build_idproperties(clip_id->properties);
/* Animation. */
build_animdata(clip_id);
build_parameters(clip_id);
@@ -1670,6 +1712,7 @@ void DepsgraphNodeBuilder::build_lightprobe(LightProbe *probe)
}
/* Placeholder so we can add relations and tag ID node for update. */
add_operation_node(&probe->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL);
+ build_idproperties(probe->id.properties);
build_animdata(&probe->id);
build_parameters(&probe->id);
}
@@ -1681,6 +1724,7 @@ void DepsgraphNodeBuilder::build_speaker(Speaker *speaker)
}
/* Placeholder so we can add relations and tag ID node for update. */
add_operation_node(&speaker->id, NodeType::AUDIO, OperationCode::SPEAKER_EVAL);
+ build_idproperties(speaker->id.properties);
build_animdata(&speaker->id);
build_parameters(&speaker->id);
if (speaker->sound != nullptr) {
@@ -1699,6 +1743,7 @@ void DepsgraphNodeBuilder::build_sound(bSound *sound)
NodeType::AUDIO,
OperationCode::SOUND_EVAL,
function_bind(BKE_sound_evaluate, _1, bmain_, sound_cow));
+ build_idproperties(sound->id.properties);
build_animdata(&sound->id);
build_parameters(&sound->id);
}
@@ -1732,6 +1777,7 @@ void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene)
/* Make sure data for sequences is in the graph. */
Sequence *seq;
SEQ_BEGIN (scene->ed, seq) {
+ build_idproperties(seq->prop);
if (seq->sound != nullptr) {
build_sound(seq->sound);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 15c1a42574f..5cd7f7449a2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -37,8 +37,8 @@ struct Collection;
struct FCurve;
struct FreestyleLineSet;
struct FreestyleLineStyle;
-struct GHash;
struct ID;
+struct IDProperty;
struct Image;
struct Key;
struct LayerCollection;
@@ -150,6 +150,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_id(ID *id);
+ virtual void build_idproperties(IDProperty *id_property);
+
virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
virtual void build_scene_parameters(Scene *scene);
virtual void build_scene_compositor(Scene *scene);
@@ -200,6 +202,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_rig(Object *object, bool is_object_visible);
virtual void build_proxy_rig(Object *object);
virtual void build_armature(bArmature *armature);
+ virtual void build_armature_bones(ListBase *bones);
virtual void build_shapekeys(Key *key);
virtual void build_camera(Camera *camera);
virtual void build_light(Light *lamp);
@@ -277,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_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index 5383e26bbd4..7a05ae36ea4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -244,6 +244,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
/* Custom properties. */
if (pchan->prop != nullptr) {
+ build_idproperties(pchan->prop);
add_operation_node(
&object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name);
}
@@ -323,6 +324,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
/* Custom properties. */
if (pchan->prop != nullptr) {
+ build_idproperties(pchan->prop);
add_operation_node(
&object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
index 1edf9826208..60e843f9124 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
@@ -57,6 +57,7 @@ void DepsgraphNodeBuilder::build_scene_parameters(Scene *scene)
return;
}
build_parameters(&scene->id);
+ build_idproperties(scene->id.properties);
add_operation_node(&scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL);
/* NOTE: This is a bit overkill and can potentially pull a bit too much into the graph, but:
*
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 11ec205eaf5..1ecae6b5d8b 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -76,8 +76,9 @@ 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"
#include "BKE_key.h"
#include "BKE_layer.h"
@@ -566,6 +567,18 @@ void DepsgraphRelationBuilder::build_id(ID *id)
}
}
+static void build_idproperties_callback(IDProperty *id_property, void *user_data)
+{
+ DepsgraphRelationBuilder *builder = reinterpret_cast<DepsgraphRelationBuilder *>(user_data);
+ BLI_assert(id_property->type == IDP_ID);
+ builder->build_id(reinterpret_cast<ID *>(id_property->data.pointer));
+}
+
+void DepsgraphRelationBuilder::build_idproperties(IDProperty *id_property)
+{
+ IDP_foreach_property(id_property, IDP_TYPE_FILTER_ID, build_idproperties_callback, this);
+}
+
void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_collection,
Object *object,
Collection *collection)
@@ -579,6 +592,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
* recurses into all the nested objects and collections. */
return;
}
+ build_idproperties(collection->id.properties);
const bool group_done = built_map_.checkIsBuiltAndTag(collection);
OperationKey object_transform_final_key(object != nullptr ? &object->id : nullptr,
NodeType::TRANSFORM,
@@ -692,6 +706,7 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
final_transform_key,
"Simulation -> Final Transform");
}
+ build_idproperties(object->id.properties);
/* Animation data */
build_animdata(&object->id);
/* Object data. */
@@ -1368,6 +1383,7 @@ void DepsgraphRelationBuilder::build_action(bAction *action)
if (built_map_.checkIsBuiltAndTag(action)) {
return;
}
+ build_idproperties(action->id.properties);
if (!BLI_listbase_is_empty(&action->curves)) {
TimeSourceKey time_src_key;
ComponentKey animation_key(&action->id, NodeType::ANIMATION);
@@ -1613,6 +1629,7 @@ void DepsgraphRelationBuilder::build_world(World *world)
if (built_map_.checkIsBuiltAndTag(world)) {
return;
}
+ build_idproperties(world->id.properties);
/* animation */
build_animdata(&world->id);
build_parameters(&world->id);
@@ -1891,6 +1908,7 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key)
if (built_map_.checkIsBuiltAndTag(key)) {
return;
}
+ build_idproperties(key->id.properties);
/* Attach animdata to geometry. */
build_animdata(&key->id);
build_parameters(&key->id);
@@ -2070,6 +2088,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
+ build_idproperties(obdata->properties);
/* Animation. */
build_animdata(obdata);
build_parameters(obdata);
@@ -2182,8 +2201,18 @@ void DepsgraphRelationBuilder::build_armature(bArmature *armature)
if (built_map_.checkIsBuiltAndTag(armature)) {
return;
}
+ build_idproperties(armature->id.properties);
build_animdata(&armature->id);
build_parameters(&armature->id);
+ build_armature_bones(&armature->bonebase);
+}
+
+void DepsgraphRelationBuilder::build_armature_bones(ListBase *bones)
+{
+ LISTBASE_FOREACH (Bone *, bone, bones) {
+ build_idproperties(bone->prop);
+ build_armature_bones(&bone->childbase);
+ }
}
void DepsgraphRelationBuilder::build_camera(Camera *camera)
@@ -2191,6 +2220,7 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera)
if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
+ build_idproperties(camera->id.properties);
build_animdata(&camera->id);
build_parameters(&camera->id);
if (camera->dof.focus_object != nullptr) {
@@ -2207,6 +2237,7 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
+ build_idproperties(lamp->id.properties);
build_animdata(&lamp->id);
build_parameters(&lamp->id);
/* light's nodetree */
@@ -2227,11 +2258,20 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (built_map_.checkIsBuiltAndTag(ntree)) {
return;
}
+ build_idproperties(ntree->id.properties);
build_animdata(&ntree->id);
build_parameters(&ntree->id);
ComponentKey shading_key(&ntree->id, NodeType::SHADING);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
+ build_idproperties(bnode->prop);
+ LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->inputs) {
+ build_idproperties(socket->prop);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->outputs) {
+ build_idproperties(socket->prop);
+ }
+
ID *id = bnode->id;
if (id == nullptr) {
continue;
@@ -2296,6 +2336,13 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
}
}
+ LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->inputs) {
+ build_idproperties(socket->prop);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->outputs) {
+ build_idproperties(socket->prop);
+ }
+
OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
OperationKey shading_parameters_key(
&ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE);
@@ -2315,6 +2362,7 @@ void DepsgraphRelationBuilder::build_material(Material *material)
if (built_map_.checkIsBuiltAndTag(material)) {
return;
}
+ build_idproperties(material->id.properties);
/* animation */
build_animdata(&material->id);
build_parameters(&material->id);
@@ -2347,6 +2395,7 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
}
/* texture itself */
ComponentKey texture_key(&texture->id, NodeType::GENERIC_DATABLOCK);
+ build_idproperties(texture->id.properties);
build_animdata(&texture->id);
build_parameters(&texture->id);
@@ -2375,6 +2424,7 @@ void DepsgraphRelationBuilder::build_image(Image *image)
if (built_map_.checkIsBuiltAndTag(image)) {
return;
}
+ build_idproperties(image->id.properties);
build_parameters(&image->id);
}
@@ -2395,6 +2445,7 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file)
if (built_map_.checkIsBuiltAndTag(cache_file)) {
return;
}
+ build_idproperties(cache_file->id.properties);
/* Animation. */
build_animdata(&cache_file->id);
build_parameters(&cache_file->id);
@@ -2424,6 +2475,7 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask)
return;
}
ID *mask_id = &mask->id;
+ build_idproperties(mask_id->properties);
/* F-Curve animation. */
build_animdata(mask_id);
build_parameters(mask_id);
@@ -2462,6 +2514,7 @@ void DepsgraphRelationBuilder::build_freestyle_linestyle(FreestyleLineStyle *lin
ID *linestyle_id = &linestyle->id;
build_parameters(linestyle_id);
+ build_idproperties(linestyle_id->properties);
build_animdata(linestyle_id);
build_nodetree(linestyle->nodetree);
}
@@ -2472,6 +2525,7 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
return;
}
/* Animation. */
+ build_idproperties(clip->id.properties);
build_animdata(&clip->id);
build_parameters(&clip->id);
}
@@ -2481,6 +2535,7 @@ void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe)
if (built_map_.checkIsBuiltAndTag(probe)) {
return;
}
+ build_idproperties(probe->id.properties);
build_animdata(&probe->id);
build_parameters(&probe->id);
}
@@ -2490,6 +2545,7 @@ void DepsgraphRelationBuilder::build_speaker(Speaker *speaker)
if (built_map_.checkIsBuiltAndTag(speaker)) {
return;
}
+ build_idproperties(speaker->id.properties);
build_animdata(&speaker->id);
build_parameters(&speaker->id);
if (speaker->sound != nullptr) {
@@ -2505,6 +2561,7 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound)
if (built_map_.checkIsBuiltAndTag(sound)) {
return;
}
+ build_idproperties(sound->id.properties);
build_animdata(&sound->id);
build_parameters(&sound->id);
}
@@ -2535,6 +2592,7 @@ void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
Sequence *seq;
bool has_audio_strips = false;
SEQ_BEGIN (scene->ed, seq) {
+ build_idproperties(seq->prop);
if (seq->sound != nullptr) {
build_sound(seq->sound);
ComponentKey sound_key(&seq->sound->id, NodeType::AUDIO);
@@ -2637,7 +2695,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;
@@ -2684,7 +2742,7 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
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;
}
@@ -2714,7 +2772,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) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index caec7cc1496..aa6d8ababd3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -54,6 +54,7 @@ struct FCurve;
struct FreestyleLineSet;
struct FreestyleLineStyle;
struct ID;
+struct IDProperty;
struct Image;
struct Key;
struct LayerCollection;
@@ -196,6 +197,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_id(ID *id);
+ virtual void build_idproperties(IDProperty *id_property);
+
virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
virtual void build_scene_parameters(Scene *scene);
virtual void build_scene_compositor(Scene *scene);
@@ -267,6 +270,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_proxy_rig(Object *object);
virtual void build_shapekeys(Key *key);
virtual void build_armature(bArmature *armature);
+ virtual void build_armature_bones(ListBase *bones);
virtual void build_camera(Camera *camera);
virtual void build_light(Light *lamp);
virtual void build_nodetree(bNodeTree *ntree);
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 7fe7695f195..b75252aa325 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -356,6 +356,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
}
/* Links between operations for each bone. */
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ build_idproperties(pchan->prop);
OperationKey bone_local_key(
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
OperationKey bone_pose_key(
@@ -464,6 +465,7 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE);
OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP);
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ build_idproperties(pchan->prop);
OperationKey bone_local_key(
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
OperationKey bone_ready_key(
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
index 08191bcecc8..410df839875 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
@@ -52,6 +52,7 @@ void DepsgraphRelationBuilder::build_scene_parameters(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_PARAMETERS)) {
return;
}
+ build_idproperties(scene->id.properties);
build_parameters(&scene->id);
OperationKey parameters_eval_key(
&scene->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT);
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 701419d24e1..08f373d486a 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;
@@ -473,7 +471,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:
@@ -569,12 +567,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 ff65ff5b050..542065d2fb3 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 bc8012158e1..b68c4b91fcc 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -25,7 +25,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
#include "DNA_object_types.h"
@@ -75,7 +74,7 @@ void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph),
/* Start with scheduling all operations from ID node. */
TraversalQueue queue;
Set<OperationNode *> scheduled;
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, target_id_node->components) {
+ 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;
@@ -88,7 +87,6 @@ void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph),
scheduled.add(op_node);
}
}
- GHASH_FOREACH_END();
/* Process the queue. */
while (!queue.empty()) {
/* get next operation node to process. */
@@ -205,13 +203,12 @@ void deg_foreach_ancestor_ID(const Depsgraph *graph,
/* Start with scheduling all operations from ID node. */
TraversalQueue queue;
Set<OperationNode *> scheduled;
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, target_id_node->components) {
+ for (ComponentNode *comp_node : target_id_node->components.values()) {
for (OperationNode *op_node : comp_node->operations) {
queue.push_back(op_node);
scheduled.add(op_node);
}
}
- GHASH_FOREACH_END();
Set<IDNode *> visited;
visited.add_new(target_id_node);
/* Process the queue. */
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 a3dc2135f78..7016d07ae72 100644
--- a/source/blender/depsgraph/intern/depsgraph_type.h
+++ b/source/blender/depsgraph/intern/depsgraph_type.h
@@ -38,11 +38,13 @@
#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;
@@ -51,14 +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 e61bcb961ae..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,7 +114,7 @@ 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_user_data(pool);
DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v;
@@ -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 75a3762192d..f0ce38ddeae 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -165,7 +165,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 5fd412f32e6..c751282a087 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" {
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index b211ac873a3..ca37401d200 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -31,7 +31,6 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-struct GHash;
struct ID;
struct bPoseChannel;
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 c1aa05df987..2381076161f 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/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
index 0dbb0542b18..b79d5753686 100644
--- a/source/blender/draw/engines/overlay/overlay_gpencil.c
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -201,7 +201,9 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
}
const bool show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
- const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0;
+ const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0 &&
+ ((ts->gpencil_v3d_align &
+ (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) == 0);
if (show_grid && show_overlays) {
const char *grid_unit = NULL;
@@ -238,6 +240,15 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
break;
}
+ /* Move the grid to the right location depending of the align type.
+ * This is required only for 3D Cursor or Origin. */
+ if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
+ copy_v3_v3(mat[3], cursor->location);
+ }
+ else if (ts->gpencil_v3d_align & GP_PROJECT_VIEWSPACE) {
+ copy_v3_v3(mat[3], ob->obmat[3]);
+ }
+
translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f);
mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit));
rescale_m4(mat, (float[3]){size[0], size[1], 0.0f});
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/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index e4da4e66e21..4c7c3a2c253 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -87,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"
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_add.c b/source/blender/editors/armature/armature_add.c
index dfb274fdefe..d941f8ce95f 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -53,6 +53,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -222,6 +223,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1049,6 +1051,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -1521,7 +1525,13 @@ static int armature_extrude_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ if (!changed_multi) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_extrude(wmOperatorType *ot)
@@ -1592,6 +1602,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1682,6 +1693,7 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 8a7afe13a2f..a7a705a6202 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -54,6 +54,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -1283,6 +1284,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
}
}
MEM_freeN(objects);
@@ -1458,6 +1460,7 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
ED_armature_edit_refresh_layer_used(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
}
}
MEM_freeN(objects);
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 3d41fd5f0c6..08d82bf13c9 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -104,6 +104,7 @@ void POSE_OT_select_all(struct wmOperatorType *ot);
void POSE_OT_select_parent(struct wmOperatorType *ot);
void POSE_OT_select_hierarchy(struct wmOperatorType *ot);
void POSE_OT_select_linked(struct wmOperatorType *ot);
+void POSE_OT_select_linked_pick(struct wmOperatorType *ot);
void POSE_OT_select_constraint_target(struct wmOperatorType *ot);
void POSE_OT_select_grouped(struct wmOperatorType *ot);
void POSE_OT_select_mirror(struct wmOperatorType *ot);
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index b304ce92a54..da1b29307b1 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -100,6 +100,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_select_parent);
WM_operatortype_append(POSE_OT_select_hierarchy);
WM_operatortype_append(POSE_OT_select_linked);
+ WM_operatortype_append(POSE_OT_select_linked_pick);
WM_operatortype_append(POSE_OT_select_constraint_target);
WM_operatortype_append(POSE_OT_select_grouped);
WM_operatortype_append(POSE_OT_select_mirror);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 644e466e904..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"
@@ -58,6 +58,7 @@
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -707,6 +708,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
if (ok) {
BKE_report(op->reports, RPT_INFO, "Separated bones");
+ ED_outliner_select_sync_from_object_tag(C);
}
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 9cd87f476d4..c10e204e3a4 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -44,6 +44,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -484,6 +485,7 @@ static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
bArmature *arm = ob->data;
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -518,6 +520,7 @@ static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
bArmature *arm = ob->data;
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 41ad5433931..ce652b0eaf4 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -454,22 +454,22 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
return OPERATOR_FINISHED;
}
-static bool pose_select_linked_poll(bContext *C)
+static bool pose_select_linked_pick_poll(bContext *C)
{
return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
}
-void POSE_OT_select_linked(wmOperatorType *ot)
+void POSE_OT_select_linked_pick(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Connected";
- ot->idname = "POSE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
+ ot->idname = "POSE_OT_select_linked_pick";
+ ot->description = "Select bones linked by parent/child connections under the mouse cursor";
/* callbacks */
/* leave 'exec' unset */
ot->invoke = pose_select_connected_invoke;
- ot->poll = pose_select_linked_poll;
+ ot->poll = pose_select_linked_pick_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -482,6 +482,62 @@ void POSE_OT_select_linked(wmOperatorType *ot)
"Extend selection instead of deselecting everything first");
}
+static int pose_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Bone *curBone, *next = NULL;
+
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
+ if ((pchan->bone->flag & BONE_SELECTED) == 0) {
+ continue;
+ }
+
+ bArmature *arm = ob->data;
+
+ /* Select parents */
+ for (curBone = pchan->bone; curBone; curBone = next) {
+ if (PBONE_SELECTABLE(arm, curBone)) {
+ curBone->flag |= BONE_SELECTED;
+
+ if (curBone->flag & BONE_CONNECTED) {
+ next = curBone->parent;
+ }
+ else {
+ next = NULL;
+ }
+ }
+ else {
+ next = NULL;
+ }
+ }
+
+ /* Select children */
+ for (curBone = pchan->bone->childbase.first; curBone; curBone = curBone->next) {
+ selectconnected_posebonechildren(ob, curBone, false);
+ }
+ ED_pose_bone_select_tag_update(ob);
+ }
+ CTX_DATA_END;
+
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Connected";
+ ot->idname = "POSE_OT_select_linked";
+ ot->description = "Select all bones linked by parent/child connections to the current selection";
+
+ /* callbacks */
+ ot->exec = pose_select_linked_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* -------------------------------------- */
static int pose_de_select_all_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index c0e5e11ac22..d6256f67066 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -58,6 +58,7 @@
#include "ED_curve.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
@@ -1500,6 +1501,8 @@ static int separate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -3589,6 +3592,7 @@ static void subdividenurb(Object *obedit, View3D *v3d, int number_cuts)
memcpy(bpn, nextbp, sizeof(BPoint));
interp_v4_v4v4(bpn->vec, bp->vec, nextbp->vec, factor);
+ bpn->radius = interpf(bp->radius, nextbp->radius, factor);
bpn++;
}
}
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 947da9e7877..4a4ade4e98f 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -77,6 +77,7 @@
#include "ED_gpencil.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_space_api.h"
@@ -4365,6 +4366,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -4545,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,
@@ -4562,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,
@@ -4740,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_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index bd7dfecf692..961c4e05a28 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -515,7 +515,6 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
float mvec[2];
float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */
float fac;
- float mpressure;
/* default angle of brush in radians */
float angle = brush->gpencil_settings->draw_angle;
@@ -543,9 +542,7 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
/* interpolate with previous point for smoother transitions */
- mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
- pt->pressure = mpressure;
-
+ pt->pressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
}
}
@@ -3151,7 +3148,6 @@ static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *p
float mvec[2];
float fac;
- float mpressure;
/* angle vector of the brush with full thickness */
float v0[2] = {cos(angle), sin(angle)};
@@ -3159,13 +3155,10 @@ static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *p
mvec[0] = pt->x - pt_prev->x;
mvec[1] = pt->y - pt_prev->y;
normalize_v2(mvec);
-
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
/* interpolate with previous point for smoother transitions */
- mpressure = interpf(pt->pressure - (sen * fac), pt_prev->pressure, 0.3f);
- pt->pressure = mpressure;
-
- CLAMP(pt->pressure, pt_prev->pressure * 0.5f, 1.0f);
+ pt->pressure = interpf(pt->pressure - (sen * fac), pt_prev->pressure, 0.3f);
+ CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
}
/* Add arc points between two mouse events using the previous segment to determine the vertice of
@@ -3241,6 +3234,7 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
corner[0] = midpoint[0] - (cp1[0] - midpoint[0]);
corner[1] = midpoint[1] - (cp1[1] - midpoint[1]);
+ tGPspoint *pt_step = pt_prev;
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
@@ -3250,9 +3244,12 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
pt->pressure = pt_prev->pressure;
pt->strength = pt_prev->strength;
- /* Apply angle of stroke to brush size. */
+ /* Apply angle of stroke to brush size to interpolated points but slightly attenuated.. */
if (brush_settings->draw_angle_factor != 0.0f) {
- gp_brush_angle_segment(p, pt_prev, pt);
+ gp_brush_angle_segment(p, pt_step, pt);
+ CLAMP(pt->pressure, pt_prev->pressure * 0.5f, 1.0f);
+ /* Use the previous interpolated point for next segment. */
+ pt_step = pt;
}
/* Apply randomness to pressure. */
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_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_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_outliner.h b/source/blender/editors/include/ED_outliner.h
index be1ee786a75..d3fc5174dd9 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -27,6 +27,7 @@
extern "C" {
#endif
+struct Base;
struct ListBase;
struct bContext;
@@ -34,7 +35,7 @@ bool ED_outliner_collections_editor_poll(struct bContext *C);
void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
-Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
+struct Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_outliner_select_sync_from_object_tag(struct bContext *C);
void ED_outliner_select_sync_from_edit_bone_tag(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/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 709e05c18b6..f4dd2da06fc 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1672,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);
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_anim.c b/source/blender/editors/interface/interface_anim.c
index ed591335660..8c9768f523d 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -35,6 +35,7 @@
#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"
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_panel.c b/source/blender/editors/interface/interface_panel.c
index f824670cc57..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;
@@ -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;
@@ -2486,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:
@@ -2537,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 1df42659bf8..2d1b3f560f7 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -1843,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,
@@ -7128,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:
*
@@ -7441,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;
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 0142f3b38e0..0d4eff2ba31 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -2095,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;
}
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 72f6535eadf..f8419ba3eba 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -1234,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;
@@ -1306,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) {
@@ -1777,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);
@@ -1793,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);
@@ -1804,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)};
@@ -1825,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);
@@ -1833,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)};
@@ -1959,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);
@@ -1973,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_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 37b0cd447b6..24c5cbb8573 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -69,6 +69,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_uvedit.h"
@@ -4404,6 +4405,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
/* delay depsgraph recalc until all objects are duplicated */
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
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/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index de9cc72dfa4..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
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 9e0a6d51614..64abd01983c 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -2048,6 +2048,7 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE, scene);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
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 1b662ccc389..bcc5bf3e1ae 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -1433,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);
@@ -1443,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);
@@ -1482,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");
}
/** \} */
@@ -1739,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
* \{ */
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/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 3ce5aeedae8..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) {
@@ -4112,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) {
@@ -4257,7 +4255,6 @@ static int brush_add(const bContext *C, PEData *data, short number)
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_reduce = brush_add_count_iter_reduce;
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index b0444f25a8c..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;
@@ -856,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;
@@ -910,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);
@@ -1033,7 +1022,7 @@ 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_user_data(pool);
WriteTaskData *task_data = (WriteTaskData *)task_data_v;
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 69cfe72308f..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) {
@@ -2583,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);
}
@@ -2638,8 +2644,10 @@ void ED_region_panels_layout_ex(const bContext *C,
y = -y;
}
- /* this also changes the 'cur' */
- UI_view2d_totRect_set(v2d, x, y);
+ if (update_tot_size) {
+ /* this also changes the 'cur' */
+ UI_view2d_totRect_set(v2d, x, y);
+ }
if (use_category_tabs) {
region->runtime.category = category;
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index b66964d0e7f..eccc15456ae 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -4388,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) {
@@ -4411,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.c b/source/blender/editors/sculpt_paint/paint_image.c
index d913bc2e242..e227db1c644 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -388,6 +388,10 @@ void paint_brush_color_get(struct Scene *scene,
break;
}
}
+ /* Gradient / Colorband colors are not considered PROP_COLOR_GAMMA.
+ * Brush colors are expected to be in sRGB though. */
+ IMB_colormanagement_scene_linear_to_srgb_v3(color_gr);
+
copy_v3_v3(color, color_gr);
}
else {
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..7bd7714b725 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++) {
@@ -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);
@@ -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);
@@ -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 4a51b3c8b8a..fe7ae7096a0 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -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) {
+ 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, 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++) {
+ 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;
@@ -1906,7 +1895,7 @@ static void draw_distortion(SpaceClip *sc,
immBegin(GPU_PRIM_LINE_STRIP, steps + 1);
- for (j = 0; j <= steps; j++) {
+ 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));
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 657635b845d..5be4b2d5df0 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -885,7 +885,7 @@ 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_user_data(pool);
MovieClip *clip = (MovieClip *)task_data;
@@ -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 b849fbd9250..3783a3af96c 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -1367,7 +1367,7 @@ 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_user_data(pool);
@@ -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/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 c04d08d7b78..7f6d0658ec8 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1264,9 +1264,7 @@ 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_user_data(pool);
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
@@ -1325,9 +1323,7 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void
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_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 3658ebae3a2..6f3ef44fe94 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -656,8 +656,8 @@ static void uiblock_layer_pass_buttons(
/* pass */
rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass) : NULL);
- if (rpass && RE_passes_have_name(rl)) {
- display_name = rpass->name;
+ if (rl && RE_passes_have_name(rl)) {
+ display_name = rpass ? rpass->name : "";
rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
but = uiDefMenuBut(block,
ui_imageuser_pass_menu,
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_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 5bcb21b152f..f8c0e66873f 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -369,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 */
@@ -469,23 +475,21 @@ static void stats_row(int col1,
*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);
+ 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)
{
- /* 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);
+ /* 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);
}
@@ -569,7 +573,7 @@ void ED_info_draw_stats(
int col2 = x + longest_label + (0.5f * U.widget_unit);
/* Add some extra margin above this section. */
- *y -= (0.5f * height);
+ *y -= (0.6f * height);
if (object_mode == OB_MODE_OBJECT) {
stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
@@ -577,6 +581,7 @@ void ED_info_draw_stats(
if (obedit) {
if (obedit->type == OB_MESH) {
+ 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);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 70f3db1e2ab..44003a5b9bc 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -73,6 +73,9 @@
#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),
@@ -94,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)
@@ -108,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)
@@ -119,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)
@@ -146,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)
@@ -197,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 */
@@ -243,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)
@@ -535,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
@@ -698,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");
@@ -717,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)) {
@@ -743,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)
@@ -790,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.
@@ -828,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);
}
@@ -839,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)
@@ -869,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,
@@ -926,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;
@@ -934,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(
@@ -960,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");
@@ -997,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");
@@ -1012,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)
@@ -1028,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);
@@ -1040,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)
@@ -1091,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);
}
}
@@ -1108,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");
@@ -1130,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)
@@ -1146,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 */
@@ -1356,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);
}
}
}
@@ -1420,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(
@@ -1447,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,
@@ -1506,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)
@@ -1517,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);
}
}
@@ -1579,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);
}
}
@@ -1598,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)
@@ -1611,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);
}
}
@@ -1660,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,
@@ -1673,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)
@@ -1683,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)
@@ -1691,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)
@@ -1712,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)
@@ -1721,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)
@@ -1749,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)
@@ -1758,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,
@@ -1772,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)
@@ -1784,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);
}
}
@@ -1809,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*/
}
@@ -1823,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,
@@ -1836,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)
@@ -1861,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)
@@ -1887,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)
{
@@ -1973,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",
"",
@@ -1988,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",
"",
@@ -2003,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);
@@ -2018,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)
@@ -2039,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) {
@@ -2065,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 {
@@ -2083,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);
}
}
@@ -2144,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)
@@ -2181,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)
@@ -2207,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,
@@ -2217,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);
@@ -2231,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,
@@ -2273,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,
@@ -2336,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(
@@ -2487,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);
}
}
@@ -2525,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);
}
}
@@ -2563,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)
@@ -2606,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);
}
}
}
@@ -2651,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);
}
}
@@ -2666,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)
@@ -2680,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,
@@ -2695,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)
@@ -2708,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 */
@@ -2958,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)
@@ -2980,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;
}
}
@@ -3071,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 */
@@ -3129,33 +3137,33 @@ static void node_simulation_buts_particle_simulation(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "name", 0, "", ICON_NONE);
+ 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", 0, "", ICON_NONE);
+ 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", 0, "", ICON_NONE);
+ 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", 0, "", ICON_NONE);
+ 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", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_simulation_set_butfunc(bNodeType *ntype)
@@ -3183,19 +3191,19 @@ static void node_simulation_set_butfunc(bNodeType *ntype)
static void node_function_buts_boolean_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_function_buts_float_compare(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_function_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_function_set_butfunc(bNodeType *ntype)
@@ -3462,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) {
@@ -3470,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;
@@ -3482,15 +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", 0, text, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
break;
}
case SOCK_IMAGE: {
- uiItemR(layout, ptr, "default_value", 0, text, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
break;
}
default:
@@ -3508,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_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 91fe6a97432..87b1f662b59 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -716,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);
}
}
@@ -741,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;
@@ -765,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, C, ntree, node, input);
+ uiTemplateNodeLink(row, C, ntree, node, input);
+ add_dummy_decorator = true;
if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
if (depth == 0) {
@@ -817,29 +805,43 @@ static void ui_node_draw_input(
}
}
else {
- row = uiLayoutRow(split, true);
+ 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:
- uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE);
- break;
- case SOCK_VECTOR:
- uiItemS(row);
- 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:
+ add_dummy_decorator = true;
}
}
}
+ if (add_dummy_decorator) {
+ uiItemDecoratorR(split_wrapper.decorate_column, NULL, NULL, 0);
+ }
+
/* clear */
node->flag &= ~NODE_TEST;
}
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_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 3032d38b7ac..f2b64bc2a4b 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -431,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);
/* ---------------------------------------------------------------- */
@@ -442,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_select.c b/source/blender/editors/space_outliner/outliner_select.c
index e87e71f0689..fa8422573ab 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -357,20 +357,24 @@ static eOLDrawState tree_element_set_active_object(bContext *C,
}
te_ob = outliner_find_id(soops, &soops->tree, (ID *)ob);
- if (te_ob != NULL) {
+ if (te_ob != NULL && te_ob != te) {
parent_tselem = TREESTORE(te_ob);
}
- if (!ELEM(NULL, parent_tselem, base)) {
+ if (base) {
if (set == OL_SETSEL_EXTEND) {
/* swap select */
if (base->flag & BASE_SELECTED) {
ED_object_base_select(base, BA_DESELECT);
- parent_tselem->flag &= ~TSE_SELECTED;
+ if (parent_tselem) {
+ parent_tselem->flag &= ~TSE_SELECTED;
+ }
}
else {
ED_object_base_select(base, BA_SELECT);
- parent_tselem->flag |= TSE_SELECTED;
+ if (parent_tselem) {
+ parent_tselem->flag |= TSE_SELECTED;
+ }
}
}
else {
@@ -386,7 +390,9 @@ static eOLDrawState tree_element_set_active_object(bContext *C,
BKE_view_layer_base_deselect_all(view_layer);
}
ED_object_base_select(base, BA_SELECT);
- parent_tselem->flag |= TSE_SELECTED;
+ if (parent_tselem) {
+ parent_tselem->flag |= TSE_SELECTED;
+ }
}
if (recursive) {
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 5db5fe6f565..172d64c9c67 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -89,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,
@@ -414,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;
@@ -502,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
@@ -643,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),
@@ -673,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) {
@@ -885,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),
@@ -937,7 +954,11 @@ static void refreshdrivers_animdata_cb(int UNUSED(event),
}
}
-/* --------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Operation Utilities
+ * \{ */
typedef enum eOutliner_PropDataOps {
OL_DOP_SELECT = 1,
@@ -1310,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 */
@@ -1332,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",
@@ -1388,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);
@@ -1435,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);
@@ -1502,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,
@@ -1802,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,
@@ -1903,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,
@@ -1929,8 +2015,6 @@ static void outliner_do_id_set_operation(
}
}
-/* ------------------------------------------ */
-
static void actionset_id_cb(TreeElement *UNUSED(te),
TreeStoreElem *tselem,
TreeStoreElem *tsep,
@@ -2028,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,
@@ -2144,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", ""},
@@ -2190,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", ""},
@@ -2235,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[] = {
@@ -2328,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)
{
@@ -2493,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 9b06de67825..7bb62b0d1e2 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -59,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"
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 83671a0d600..e615e7be92f 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -56,6 +56,7 @@
#include "ED_anim_api.h"
#include "ED_numinput.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
#include "ED_space_api.h"
@@ -3561,6 +3562,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ ED_outliner_select_sync_from_sequence_tag(C);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index b6bf390b2f6..fac378ae104 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -102,7 +102,7 @@
#define M_GOLDEN_RATIO_CONJUGATE 0.618033988749895f
-#define VIEW3D_OVERLAY_LINEHEIGHT (0.8f * U.widget_unit)
+#define VIEW3D_OVERLAY_LINEHEIGHT (0.9f * U.widget_unit)
/* -------------------------------------------------------------------- */
/** \name General Functions
@@ -1576,7 +1576,7 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
draw_grid_unit_name(scene, rv3d, v3d, xoffset, &yoffset);
}
- DRW_draw_region_engine_info(xoffset, yoffset);
+ DRW_draw_region_engine_info(xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT);
}
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_STATS)) {
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index a53262df267..1ad3f8bb1f5 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -47,6 +47,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h"
@@ -117,6 +118,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted);
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 f4ea0beadb6..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;
@@ -926,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 eeae4f83470..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;
@@ -2286,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 17d210f57b9..35bb7e3f0d8 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -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;
}
@@ -685,6 +687,9 @@ void createTransPose(TransInfo *t)
if (mirror) {
int total_mirrored = 0;
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ /* Clear the MIRROR flag from previous runs. */
+ pchan->bone->flag &= ~BONE_TRANSFORM_MIRROR;
+
if ((pchan->bone->flag & BONE_TRANSFORM) &&
BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) {
total_mirrored++;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 485ceb2c209..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 (orientation >= V3D_ORIENT_CUSTOM) {
- if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
- orientation = V3D_ORIENT_GLOBAL;
+ 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 ((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")) &&
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_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_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 0e8aafad7ac..d3c85b891c6 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -56,10 +56,10 @@ 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
- intern/MOD_gpenciltexture.c
MOD_gpencil_modifiertypes.h
)
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
index d3d6fc470f7..15e069fc162 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
@@ -141,7 +141,7 @@ static void bakeModifier(struct Main *UNUSED(bmain),
}
GpencilModifierTypeInfo modifierType_Gpencil_Texture = {
- /* name */ "Texture",
+ /* name */ "Texture Mapping",
/* structName */ "TextureGpencilModifierData",
/* structSize */ sizeof(TextureGpencilModifierData),
/* type */ eGpencilModifierTypeType_Gpencil,
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 5a5dfb3e1e8..f91a13a3b62 100644
--- a/source/blender/gpu/intern/gpu_immediate.c
+++ b/source/blender/gpu/intern/gpu_immediate.c
@@ -268,7 +268,8 @@ void immBegin(GPUPrimType prim_type, uint vertex_len)
else {
/* orphan this buffer & start with a fresh one */
/* this method works on all platforms, old & new */
- glBufferData(GL_ARRAY_BUFFER, active_buffer->buffer_size, NULL, GL_DYNAMIC_DRAW);
+ /* `GL_DYNAMIC_DRAW` was causing problems when closing temporary windows on old AMD GPUs. */
+ glBufferData(GL_ARRAY_BUFFER, active_buffer->buffer_size, NULL, GL_STATIC_DRAW);
active_buffer->buffer_offset = 0;
}
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/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index e6f0f44b2b3..7ebbd1a7409 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -338,7 +338,7 @@ 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_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,9 +398,7 @@ 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_user_data(pool);
int start_scanline = POINTER_AS_INT(taskdata);
@@ -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 ba1485004ae..289f8c7a7b9 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -106,6 +106,18 @@ enum {
IDP_NUMTYPES = 10,
};
+/** Used by some IDP utils, keep values in sync with type enum above. */
+enum {
+ IDP_TYPE_FILTER_STRING = 1 << 0,
+ IDP_TYPE_FILTER_INT = 1 << 1,
+ IDP_TYPE_FILTER_FLOAT = 1 << 2,
+ IDP_TYPE_FILTER_ARRAY = 1 << 5,
+ IDP_TYPE_FILTER_GROUP = 1 << 6,
+ IDP_TYPE_FILTER_ID = 1 << 7,
+ IDP_TYPE_FILTER_DOUBLE = 1 << 8,
+ IDP_TYPE_FILTER_IDPARRAY = 1 << 9,
+};
+
/*->subtype */
/* IDP_STRING */
diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h
index 166b3c22932..6583aa2eeee 100644
--- a/source/blender/makesdna/DNA_fluid_types.h
+++ b/source/blender/makesdna/DNA_fluid_types.h
@@ -393,7 +393,6 @@ typedef struct FluidDomainSettings {
float surface_tension;
float viscosity_base;
int viscosity_exponent;
- float domain_size;
/* Mesh options. */
float mesh_concave_upper;
@@ -404,7 +403,7 @@ typedef struct FluidDomainSettings {
int mesh_scale;
int totvert;
short mesh_generator;
- char _pad5[2]; /* Unused. */
+ char _pad5[6]; /* Unused. */
/* Secondary particle options. */
int particle_type;
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 1714ec8b498..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
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/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 d89bdcd074f..86860e5e14b 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -1687,11 +1687,6 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"e.g. 5*10^-6)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
- prop = RNA_def_property(srna, "domain_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.001, 10000.0);
- RNA_def_property_ui_text(prop, "Meters", "Domain size in meters (longest domain side)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
-
/* mesh options options */
prop = RNA_def_property(srna, "mesh_concave_upper", PROP_FLOAT, PROP_NONE);
@@ -2472,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 63fe1cf05ca..b36cc493447 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -1471,7 +1471,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Info", "Layer name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilLayer_info_set");
RNA_def_struct_name_property(srna, prop);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, NULL);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, "rna_GPencil_update");
/* Frames */
prop = RNA_def_property(srna, "frames", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index cb16dae7afa..1906c663c54 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -132,7 +132,7 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
{eGpencilModifierType_Texture,
"GP_TEXTURE",
ICON_TEXTURE,
- "Texture",
+ "Texture Mapping",
"Change stroke uv texture values"},
{0, NULL, 0, NULL, NULL},
};
@@ -2166,18 +2166,19 @@ static void rna_def_modifier_gpenciltexture(BlenderRNA *brna)
};
static const EnumPropertyItem mode_items[] = {
- {STROKE, "STROKE", 0, "Stroke UVs", "Manipulate only stroke UVs"},
- {FILL, "FILL", 0, "Fill UVs", "Manipulate only fill UVs"},
+ {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 UVs",
- "Manipulate both stroke and fill UVs"},
+ "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 UVs Modifier");
+ 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);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index c32a88b9918..7727f68c4c0 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", ""},
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 9242ad7237f..8089aa389c9 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -203,7 +203,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
"Round A to the nearest integer. Round upward if the fraction part is 0.5"},
{NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "The largest integer smaller than or equal A"},
{NODE_MATH_CEIL, "CEIL", 0, "Ceil", "The smallest integer greater than or equal A"},
- {NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "trunc(A)"},
+ {NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "The integer part of A, removing fractional digits"},
{0, "", ICON_NONE, NULL, NULL},
{NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"},
{NODE_MATH_MODULO, "MODULO", 0, "Modulo", "Modulo using fmod(A,B)"},
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_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_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_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index 49492200021..b54d5fed390 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -225,8 +225,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
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;
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index 4c4c25ec449..e842e81f97f 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -1231,10 +1231,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
MEM_freeN(poly_nors);
}
- if (numPolys == 0 && numVerts != 0) {
- modifier_setError(md, "Faces needed for useful output");
- }
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index b3c5313999f..d237b55e900 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -149,7 +149,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
const uint numLoops = (uint)mesh->totloop;
if (numPolys == 0 && numVerts != 0) {
- modifier_setError(md, "Faces needed for useful output");
return mesh;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index 10de192277b..382459993b7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -86,6 +86,12 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree,
{
bNodeSocket *sock = BLI_findstring(&node->outputs, name, offsetof(bNodeSocket, name));
+ /* Replace if types don't match. */
+ if (sock && sock->type != type) {
+ nodeRemoveSocket(ntree, node, sock);
+ sock = NULL;
+ }
+
/* Create socket if it doesn't exist yet. */
if (sock == NULL) {
if (rres_index >= 0) {
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/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/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_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 1e25d73a86d..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) {
@@ -807,6 +794,36 @@ void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
}
}
+/* Update window size and position based on data from GHOST window. */
+static bool wm_window_update_size_position(wmWindow *win)
+{
+ GHOST_RectangleHandle client_rect;
+ int l, t, r, b, scr_w, scr_h;
+ int sizex, sizey, posx, posy;
+
+ client_rect = GHOST_GetClientBounds(win->ghostwin);
+ GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
+
+ GHOST_DisposeRectangle(client_rect);
+
+ wm_get_desktopsize(&scr_w, &scr_h);
+ sizex = r - l;
+ sizey = b - t;
+ posx = l;
+ posy = scr_h - t - win->sizey;
+
+ if (win->sizex != sizex || win->sizey != sizey || win->posx != posx || win->posy != posy) {
+ win->sizex = sizex;
+ win->sizey = sizey;
+ win->posx = posx;
+ win->posy = posy;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
/**
* new window, no screen yet, but we open ghostwindow for it,
* also gets the window level handlers
@@ -941,12 +958,19 @@ wmWindow *WM_window_open_temp(bContext *C,
ED_area_newspace(C, area, space_type, false);
ED_screen_change(C, screen);
- ED_screen_refresh(wm, win); /* test scale */
if (win->ghostwin) {
+ /* Set size in GHOST window and then update size and position from GHOST,
+ * in case they where changed by GHOST to fit the monitor/screen. */
wm_window_set_size(win, win->sizex, win->sizey);
- wm_window_raise(win);
+ wm_window_update_size_position(win);
+ }
+ /* Refresh screen dimensions, after the effective window size is known. */
+ ED_screen_refresh(wm, win);
+
+ if (win->ghostwin) {
+ wm_window_raise(win);
GHOST_SetTitle(win->ghostwin, title);
return win;
}
@@ -1354,21 +1378,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* win32: gives undefined window size when minimized */
if (state != GHOST_kWindowStateMinimized) {
- GHOST_RectangleHandle client_rect;
- int l, t, r, b, scr_w, scr_h;
- int sizex, sizey, posx, posy;
-
- client_rect = GHOST_GetClientBounds(win->ghostwin);
- GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
-
- GHOST_DisposeRectangle(client_rect);
-
- wm_get_desktopsize(&scr_w, &scr_h);
- sizex = r - l;
- sizey = b - t;
- posx = l;
- posy = scr_h - t - win->sizey;
-
/*
* Ghost sometimes send size or move events when the window hasn't changed.
* One case of this is using compiz on linux. To alleviate the problem
@@ -1377,15 +1386,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
* It might be good to eventually do that at Ghost level, but that is for
* another time.
*/
- if (win->sizex != sizex || win->sizey != sizey || win->posx != posx ||
- win->posy != posy) {
+ if (wm_window_update_size_position(win)) {
const bScreen *screen = WM_window_get_active_screen(win);
- win->sizex = sizex;
- win->sizey = sizey;
- win->posx = posx;
- win->posy = posy;
-
/* debug prints */
if (G.debug & G_DEBUG_EVENTS) {
const char *state_str;
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/blender.map b/source/creator/blender.map
index fda6c37b10d..7720ad2b56c 100644
--- a/source/creator/blender.map
+++ b/source/creator/blender.map
@@ -18,14 +18,12 @@ local:
*cineon*;
*COLLADA*;
cu*;
- decodeInstruction;
*default_error_condition*;
*dpx*;
*embree*;
ff_*;
fftw*;
FLAC*;
- ForceStackAlign;
FT_*;
*GeneratedSaxParser*;
*google*;
@@ -40,14 +38,11 @@ local:
jack_*;
jpeg_*;
jsimd**;
- _Jv_RegisterClasses;
lame_*;
*llvm*;
*LLVM*;
*MathML*;
*mkldnn*;
- Name;
- NumNamedVarArgParams;
oc_*;
ogg*;
*oidn*;
@@ -72,8 +67,46 @@ local:
vp9*;
vpx*;
x264_*;
- X86CompilationCallback*;
xml*;
xvid*;
*YAML*;
+
+ /* LLVM symbols not in the LLVM namespace that can conflict with LLVM usage
+ * in OpenGL and OpenCL drivers. */
+ decodeInstruction;
+ EnableHotColdSplit;
+ EnableIPRA;
+ EnableOrderFileInstrumentation;
+ EnableVPlanNativePath;
+ EnableVPlanPredication;
+ FlattenedProfileUsed;
+ ForceStackAlign;
+ ForceSummaryEdgesCold;
+ FSEC;
+ __jit_debug_descriptor;
+ __jit_debug_register_code;
+ _Jv_RegisterClasses;
+ MachineRegionInfoPassID;
+ MemOPSizeLarge;
+ MemOPSizeRange;
+ MISchedPostRA;
+ ModuleSummaryDotFile;
+ __morestack;
+ Name;
+ NumNamedVarArgParams;
+ PGOViewCounts;
+ PrintBlockFreqFuncName;
+ PrintBranchProbFuncName;
+ ProfileLikelyProb;
+ StartAfterOptName;
+ StartBeforeOptName;
+ StaticLikelyProb;
+ StopAfterOptName;
+ StopBeforeOptName;
+ UseDbgAddr;
+ ViewBlockFreqFuncName;
+ ViewBlockLayoutWithBFI;
+ ViewHotFreqPercent;
+ WriteRelBFToSummary;
+ X86CompilationCallback*;
};
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/tests/CMakeLists.txt b/tests/CMakeLists.txt
index a3d4b2a501e..80d749c7040 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -39,7 +39,8 @@ unset(_default_test_python_exe)
# set(TEST_BLENDER_EXE valgrind --track-origins=yes --error-limit=no ${TEST_BLENDER_EXE})
# Standard Blender arguments for running tests.
-set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup)
+# Specify exit code so that if a Python script error happens, the test fails.
+set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --python-exit-code 1)
# Python CTests
if(WITH_BLENDER AND WITH_PYTHON)
diff --git a/tests/gtests/blenkernel/BKE_armature_test.cc b/tests/gtests/blenkernel/BKE_armature_test.cc
index 0f390a471d7..ed6045081d4 100644
--- a/tests/gtests/blenkernel/BKE_armature_test.cc
+++ b/tests/gtests/blenkernel/BKE_armature_test.cc
@@ -23,7 +23,7 @@
#include "testing/testing.h"
-static const float FLOAT_EPSILON = 1e-7;
+static const float FLOAT_EPSILON = 1.2e-7;
TEST(mat3_vec_to_roll, UnitMatrix)
{
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/tests/gtests/blenkernel/CMakeLists.txt b/tests/gtests/blenkernel/CMakeLists.txt
index bbc274c5ddb..5cf4c7a27af 100644
--- a/tests/gtests/blenkernel/CMakeLists.txt
+++ b/tests/gtests/blenkernel/CMakeLists.txt
@@ -23,7 +23,9 @@ set(INC
..
../../../source/blender/blenkernel
../../../source/blender/blenlib
+ ../../../source/blender/editors/include
../../../source/blender/makesdna
+ ../../../source/blender/makesrna
../../../intern/guardedalloc
../../../intern/atomic
)
@@ -39,3 +41,4 @@ if(WITH_BUILDINFO)
endif()
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_linklist_lockfree_test.cc b/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc
index d1176527cb5..023d02e5075 100644
--- a/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc
+++ b/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc
@@ -63,7 +63,7 @@ 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_user_data(pool);
CHECK_NOTNULL(list);
@@ -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 2d052635c88..5a19216fa7c 100644
--- a/tests/gtests/blenlib/BLI_map_test.cc
+++ b/tests/gtests/blenlib/BLI_map_test.cc
@@ -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_set_test.cc b/tests/gtests/blenlib/BLI_set_test.cc
index dc163e752d8..90c052d7d2b 100644
--- a/tests/gtests/blenlib/BLI_set_test.cc
+++ b/tests/gtests/blenlib/BLI_set_test.cc
@@ -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)
@@ -191,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_task_test.cc b/tests/gtests/blenlib/BLI_task_test.cc
index fe0f481d469..ed300b3f238 100644
--- a/tests/gtests/blenlib/BLI_task_test.cc
+++ b/tests/gtests/blenlib/BLI_task_test.cc
@@ -54,7 +54,7 @@ TEST(task, RangeIter)
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;
diff --git a/tests/gtests/blenlib/BLI_vector_set_test.cc b/tests/gtests/blenlib/BLI_vector_set_test.cc
index 816d5d653a5..bfdd47ccb13 100644
--- a/tests/gtests/blenlib/BLI_vector_set_test.cc
+++ b/tests/gtests/blenlib/BLI_vector_set_test.cc
@@ -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)
@@ -70,8 +71,10 @@ TEST(vector_set, MoveAssignment)
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 1585b77675b..e5a1ca2b200 100644
--- a/tests/gtests/blenlib/BLI_vector_test.cc
+++ b/tests/gtests/blenlib/BLI_vector_test.cc
@@ -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/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 753bc7c5b91..a3df01fdbe2 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -185,6 +185,22 @@ add_blender_test(
)
add_blender_test(
+ physics_cloth
+ ${TEST_SRC_DIR}/physics/cloth_test.blend
+ --python ${TEST_PYTHON_DIR}/physics_cloth.py
+ --
+ --run-all-tests
+)
+
+add_blender_test(
+ physics_softbody
+ ${TEST_SRC_DIR}/physics/softbody_test.blend
+ --python ${TEST_PYTHON_DIR}/physics_softbody.py
+ --
+ --run-all-tests
+)
+
+add_blender_test(
constraints
--python ${CMAKE_CURRENT_LIST_DIR}/bl_constraints.py
--
diff --git a/tests/python/bevel_operator.py b/tests/python/bevel_operator.py
index 3cdbeb9300b..884bd356b96 100644
--- a/tests/python/bevel_operator.py
+++ b/tests/python/bevel_operator.py
@@ -176,9 +176,4 @@ def main():
if __name__ == "__main__":
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/bl_alembic_io_test.py b/tests/python/bl_alembic_io_test.py
index 2786a2db4d7..b9eca3057e7 100644
--- a/tests/python/bl_alembic_io_test.py
+++ b/tests/python/bl_alembic_io_test.py
@@ -375,12 +375,4 @@ def main():
if __name__ == "__main__":
- import traceback
- # So a python error exits Blender itself too
- try:
- main()
- except SystemExit:
- raise
- except:
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/bl_blendfile_io.py b/tests/python/bl_blendfile_io.py
index 0b055b9d46a..ab06e313566 100644
--- a/tests/python/bl_blendfile_io.py
+++ b/tests/python/bl_blendfile_io.py
@@ -77,9 +77,4 @@ def main():
if __name__ == '__main__':
import sys
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/bl_blendfile_liblink.py b/tests/python/bl_blendfile_liblink.py
index 7d93d7c8455..d1cc7efc7fd 100644
--- a/tests/python/bl_blendfile_liblink.py
+++ b/tests/python/bl_blendfile_liblink.py
@@ -75,9 +75,4 @@ def main():
if __name__ == '__main__':
import sys
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/bl_bundled_modules.py b/tests/python/bl_bundled_modules.py
index 3ef5040af01..d3fe2861d9e 100644
--- a/tests/python/bl_bundled_modules.py
+++ b/tests/python/bl_bundled_modules.py
@@ -21,7 +21,7 @@
# Test that modules we ship with our Python installation are available
import bz2
-import cffi
+import ctypes
import lzma
import numpy
import sqlite3
diff --git a/tests/python/bl_constraints.py b/tests/python/bl_constraints.py
index 13a431541bc..9fce8acc84e 100644
--- a/tests/python/bl_constraints.py
+++ b/tests/python/bl_constraints.py
@@ -255,12 +255,4 @@ def main():
if __name__ == "__main__":
- import traceback
- # So a python error exits Blender itself too
- try:
- main()
- except SystemExit:
- raise
- except:
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/bl_load_addons.py b/tests/python/bl_load_addons.py
index f0c2f3f7fdf..01f0b4d72d8 100644
--- a/tests/python/bl_load_addons.py
+++ b/tests/python/bl_load_addons.py
@@ -144,11 +144,4 @@ def main():
if __name__ == "__main__":
-
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py
index 5d1a5dd8ee0..c6ad53b1f74 100644
--- a/tests/python/bl_load_py_modules.py
+++ b/tests/python/bl_load_py_modules.py
@@ -234,10 +234,4 @@ def main():
if __name__ == "__main__":
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/bl_mesh_modifiers.py b/tests/python/bl_mesh_modifiers.py
index 80f810ffad8..746e7a183a3 100644
--- a/tests/python/bl_mesh_modifiers.py
+++ b/tests/python/bl_mesh_modifiers.py
@@ -842,17 +842,7 @@ if __name__ == "__main__":
print("Load Handler:", bpy.data.filepath)
if load_handler.first is False:
bpy.app.handlers.scene_update_post.remove(load_handler)
- try:
- main()
- import sys
- sys.exit(0)
- except:
- import traceback
- traceback.print_exc()
-
- # import sys
- # sys.exit(1) # comment to debug
-
+ main()
else:
load_handler.first = False
diff --git a/tests/python/bl_mesh_validate.py b/tests/python/bl_mesh_validate.py
index 47a5e5efe47..8c5d914f92a 100644
--- a/tests/python/bl_mesh_validate.py
+++ b/tests/python/bl_mesh_validate.py
@@ -152,10 +152,4 @@ def main():
if __name__ == "__main__":
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/bl_pyapi_idprop_datablock.py b/tests/python/bl_pyapi_idprop_datablock.py
index 648b63d1637..44fec6a9043 100644
--- a/tests/python/bl_pyapi_idprop_datablock.py
+++ b/tests/python/bl_pyapi_idprop_datablock.py
@@ -20,7 +20,6 @@ import bpy
import sys
import os
import tempfile
-import traceback
import inspect
from bpy.types import UIList
@@ -331,11 +330,4 @@ def main():
if __name__ == "__main__":
- try:
- main()
- except:
- import traceback
-
- traceback.print_exc()
- sys.stderr.flush()
- os._exit(1)
+ main()
diff --git a/tests/python/bl_test.py b/tests/python/bl_test.py
index 173d575a912..6315ffbfa9d 100644
--- a/tests/python/bl_test.py
+++ b/tests/python/bl_test.py
@@ -136,12 +136,7 @@ def main():
print(" Running: '%s'" % run)
print(" MD5: '%s'!" % md5)
- try:
- result = eval(run)
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
+ result = eval(run)
if write_blend is not None:
print(" Writing Blend: %s" % write_blend)
@@ -188,10 +183,4 @@ def main():
if __name__ == "__main__":
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/boolean_operator.py b/tests/python/boolean_operator.py
index b05e60eea6c..5a674c35a47 100644
--- a/tests/python/boolean_operator.py
+++ b/tests/python/boolean_operator.py
@@ -60,9 +60,4 @@ def main():
if __name__ == "__main__":
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/modifiers.py b/tests/python/modifiers.py
index 697cddc9ba2..5e032f658af 100644
--- a/tests/python/modifiers.py
+++ b/tests/python/modifiers.py
@@ -255,9 +255,4 @@ def main():
if __name__ == "__main__":
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/modules/mesh_test.py b/tests/python/modules/mesh_test.py
index f188d998884..af0e78257d5 100644
--- a/tests/python/modules/mesh_test.py
+++ b/tests/python/modules/mesh_test.py
@@ -73,6 +73,28 @@ class ModifierSpec:
" with parameters: " + str(self.modifier_parameters)
+class PhysicsSpec:
+ """
+ Holds one Physics modifier and its parameters.
+ """
+
+ def __init__(self, modifier_name: str, modifier_type: str, modifier_parameters: dict, frame_end: int):
+ """
+ Constructs a physics spec.
+ :param modifier_name: str - name of object modifier, e.g. "Cloth"
+ :param modifier_type: str - type of object modifier, e.g. "CLOTH"
+ :param modifier_parameters: dict - {name : val} dictionary giving modifier parameters, e.g. {"quality" : 4}
+ :param frame_end:int - the last frame of the simulation at which it is baked
+ """
+ self.modifier_name = modifier_name
+ self.modifier_type = modifier_type
+ self.modifier_parameters = modifier_parameters
+ self.frame_end = frame_end
+
+ def __str__(self):
+ return "Physics Modifier: " + self.modifier_name + " of type " + self.modifier_type + \
+ " with parameters: " + str(self.modifier_parameters) + " with frame end: " + str(self.frame_end)
+
class OperatorSpec:
"""
Holds one operator and its parameters.
@@ -105,7 +127,7 @@ class MeshTest:
the public method run_test().
"""
- def __init__(self, test_object_name: str, expected_object_name: str, operations_stack=None, apply_modifiers=False):
+ def __init__(self, test_object_name: str, expected_object_name: str, operations_stack=None, apply_modifiers=False, threshold=None):
"""
Constructs a MeshTest object. Raises a KeyError if objects with names expected_object_name
or test_object_name don't exist.
@@ -125,6 +147,7 @@ class MeshTest:
type(operation)))
self.operations_stack = operations_stack
self.apply_modifier = apply_modifiers
+ self.threshold = threshold
self.verbose = os.environ.get("BLENDER_VERBOSE") is not None
self.update = os.getenv('BLENDER_TEST_UPDATE') is not None
@@ -235,6 +258,49 @@ class MeshTest:
if self.apply_modifier:
bpy.ops.object.modifier_apply(modifier=modifier_spec.modifier_name)
+
+ def _bake_current_simulation(self, obj, test_mod_type, test_mod_name, frame_end):
+ for scene in bpy.data.scenes:
+ for modifier in obj.modifiers:
+ if modifier.type == test_mod_type:
+ obj.modifiers[test_mod_name].point_cache.frame_end = frame_end
+ override = {'scene': scene, 'active_object': obj, 'point_cache': modifier.point_cache}
+ bpy.ops.ptcache.bake(override, bake=True)
+ break
+
+ def _apply_physics_settings(self, test_object, physics_spec: PhysicsSpec):
+ """
+ Apply Physics settings to test objects.
+ """
+ scene = bpy.context.scene
+ scene.frame_set(1)
+ modifier = test_object.modifiers.new(physics_spec.modifier_name,
+ physics_spec.modifier_type)
+ physics_setting = modifier.settings
+ if self.verbose:
+ print("Created modifier '{}' of type '{}'.".
+ format(physics_spec.modifier_name, physics_spec.modifier_type))
+
+
+ for param_name in physics_spec.modifier_parameters:
+ try:
+ setattr(physics_setting, param_name, physics_spec.modifier_parameters[param_name])
+ if self.verbose:
+ print("\t set parameter '{}' with value '{}'".
+ format(param_name, physics_spec.modifier_parameters[param_name]))
+ except AttributeError:
+ # Clean up first
+ bpy.ops.object.delete()
+ raise AttributeError("Modifier '{}' has no parameter named '{}'".
+ format(physics_spec.modifier_type, param_name))
+
+ scene.frame_set(physics_spec.frame_end + 1)
+
+ self._bake_current_simulation(test_object, physics_spec.modifier_type, physics_spec.modifier_name, physics_spec.frame_end)
+ if self.apply_modifier:
+ bpy.ops.object.modifier_apply(modifier=physics_spec.modifier_name)
+
+
def _apply_operator(self, test_object, operator: OperatorSpec):
"""
Apply operator on test object.
@@ -302,9 +368,12 @@ class MeshTest:
elif isinstance(operation, OperatorSpec):
self._apply_operator(evaluated_test_object, operation)
+
+ elif isinstance(operation, PhysicsSpec):
+ self._apply_physics_settings(evaluated_test_object, operation)
else:
- raise ValueError("Expected operation of type {} or {}. Got {}".
- format(type(ModifierSpec), type(OperatorSpec),
+ raise ValueError("Expected operation of type {} or {} or {}. Got {}".
+ format(type(ModifierSpec), type(OperatorSpec), type(PhysicsSpec),
type(operation)))
# Compare resulting mesh with expected one.
@@ -312,7 +381,10 @@ class MeshTest:
print("Comparing expected mesh with resulting mesh...")
evaluated_test_mesh = evaluated_test_object.data
expected_mesh = self.expected_object.data
- compare_result = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh)
+ if self.threshold:
+ compare_result = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh, threshold=self.threshold)
+ else:
+ compare_result = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh)
compare_success = (compare_result == 'Same')
# Also check if invalid geometry (which is never expected) had to be corrected...
@@ -434,7 +506,7 @@ class ModifierTest:
>>> modifiers_test.run_all_tests()
"""
- def __init__(self, modifier_tests: list, apply_modifiers=False):
+ def __init__(self, modifier_tests: list, apply_modifiers=False, threshold=None):
"""
Construct a modifier test.
:param modifier_tests: list - list of modifier test cases. Each element in the list must contain the following
@@ -445,6 +517,7 @@ class ModifierTest:
"""
self.modifier_tests = modifier_tests
self.apply_modifiers = apply_modifiers
+ self.threshold = threshold
self.verbose = os.environ.get("BLENDER_VERBOSE") is not None
self._failed_tests_list = []
@@ -461,7 +534,7 @@ class ModifierTest:
expected_object_name = case[1]
spec_list = case[2]
- test = MeshTest(test_object_name, expected_object_name)
+ test = MeshTest(test_object_name, expected_object_name, threshold=self.threshold)
if self.apply_modifiers:
test.apply_modifier = True
diff --git a/tests/python/operators.py b/tests/python/operators.py
index c5b3ac745c6..626aaedc724 100644
--- a/tests/python/operators.py
+++ b/tests/python/operators.py
@@ -163,10 +163,4 @@ def main():
if __name__ == "__main__":
- try:
- main()
- except:
- import traceback
-
- traceback.print_exc()
- sys.exit(1)
+ main()
diff --git a/tests/python/physics_cloth.py b/tests/python/physics_cloth.py
new file mode 100644
index 00000000000..5b9151ea089
--- /dev/null
+++ b/tests/python/physics_cloth.py
@@ -0,0 +1,51 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import os
+import sys
+
+import bpy
+
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from modules.mesh_test import ModifierTest, PhysicsSpec
+
+
+def main():
+ test = [
+ ["testCloth", "expectedCloth",
+ [PhysicsSpec('Cloth', 'CLOTH', {'quality': 5}, 35)]],
+ ]
+ cloth_test = ModifierTest(test, threshold=1e-3)
+
+ command = list(sys.argv)
+ for i, cmd in enumerate(command):
+ if cmd == "--run-all-tests":
+ cloth_test.apply_modifiers = True
+ cloth_test.run_all_tests()
+ break
+ elif cmd == "--run-test":
+ cloth_test.apply_modifiers = False
+ index = int(command[i + 1])
+ cloth_test.run_test(index)
+ break
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/python/physics_softbody.py b/tests/python/physics_softbody.py
new file mode 100644
index 00000000000..8d431be742c
--- /dev/null
+++ b/tests/python/physics_softbody.py
@@ -0,0 +1,51 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import os
+import sys
+
+import bpy
+
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from modules.mesh_test import ModifierTest, PhysicsSpec
+
+
+def main():
+ test = [
+ ["testSoftBody", "expectedSoftBody",
+ [PhysicsSpec('Softbody', 'SOFT_BODY', {'use_goal': False, 'bend': 8, 'pull': 0.8, 'push': 0.8}, 45)]],
+ ]
+ softBody_test = ModifierTest(test)
+
+ command = list(sys.argv)
+ for i, cmd in enumerate(command):
+ if cmd == "--run-all-tests":
+ softBody_test.apply_modifiers = True
+ softBody_test.run_all_tests()
+ break
+ elif cmd == "--run-test":
+ softBody_test.apply_modifiers = False
+ index = int(command[i + 1])
+ softBody_test.run_test(index)
+ break
+
+
+if __name__ == "__main__":
+ main()